BufferedInputStream auslesen mit Bitverschiebung

Status
Nicht offen für weitere Antworten.

0001001

Bekanntes Mitglied
Kann mir jemand mit folgender Methode helfen, die ich im Netz gefunden habe, helfen:

Code:
	public byte[] read(BufferedInputStream inputtream) throws Exception{

		byte[] pSize = new byte[4];
		int nTotal = 0;
		int nRead = 0;
		while(nTotal<4){	
			nRead = inputtream.read(pSize,nTotal,4-nTotal);
			if(nRead<0) break;
			nTotal += nRead;
		}
		int nSize = (pSize[0]&0x000000ff)|((pSize[1]&0x000000ff)<<8)|((pSize[2]&0x000000ff)<<16)|((pSize[3]&0x000000ff)<<24);
		
		if(nSize==0){
			return "".getBytes();
		}
		byte[] pData = new byte[nSize];
		nTotal = 0;
		nRead = 0;
		while(nTotal<nSize){	
			nRead = inputtream.read(pData,nTotal,nSize-nTotal);
			if(nRead<0) break;
			nTotal += nRead;
		}
		return pData;
	}

Das die Methode einen Stream ausliest und das Ergebnis in einem byte[] zurückgibt ist mir klar. Allerding verstehe ich die Zeile:
Code:
		int nSize = (pSize[0]&0x000000ff)|((pSize[1]&0x000000ff)<<8)|((pSize[2]&0x000000ff)<<16)|((pSize[3]&0x000000ff)<<24);
nicht.

Kann mir das jemand erklären?
 
In der Datei steht zu Beginn eine Art Header, in dem mindestens die Größe der eigentlichen Daten vermerkt ist, und zwar in 4 Bytes mit Little-Endian-Ordnung. Diese Bytes für die Größenangabe werden in der Zeile zu einem int zusammengezogen, um sie für Java zur Angabe der Arraygröße nutzbar/verarbeitbar zu machen.

BTW: Der Code ist vergleichsweise umständlich geschrieben (und damit meine ich nicht nur die genannte Zeile).

Ark
 
Ich würde die Methode gerne verwenden, weil die Methode laut Autor unabhängig von der Kodierung der Daten im Stream ist.

Allerdings wirft die Methode unter Umständen eine OutOfMemoryError Exception, wie hier zu sehen ist:

Füttert man folgende Demo mit einer Textdatei mit dem Inhalt:
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

Code:
import java.io.BufferedInputStream;
import java.io.FileInputStream;

public class Test {
	public static void main(String[] args) {
		new Test().start();
	}
	
	public void start(){
		try {
			BufferedInputStream in = new BufferedInputStream( new FileInputStream("test.txt") );
			byte[] b = read(in);
		} catch (Exception e) {
			e.printStackTrace();
		} 
	}

	
	public static final byte[] read(BufferedInputStream inStream) throws Exception{
		byte[] pSize = new byte[4];
		int nTotal = 0;
		int nRead = 0;
		while(nTotal<4){	
			nRead = inStream.read(pSize,nTotal,4-nTotal);
			if(nRead<0) break;
			nTotal += nRead;
		}
		int nSize = (pSize[0]&0x000000ff)|((pSize[1]&0x000000ff)<<8)|((pSize[2]&0x000000ff)<<16)|((pSize[3]&0x000000ff)<<24);

		if(nSize==0){
			return "".getBytes();
		}
		byte[] pData = new byte[nSize];
		nTotal = 0;
		nRead = 0;
		while(nTotal<nSize){	
			nRead = inStream.read(pData,nTotal,nSize-nTotal);
			if(nRead<0) break;
			nTotal += nRead;
		}
		return pData;
	}
}

Die Frage ist nun, warum fliegt diese Exception?
 
0001001 hat gesagt.:
Ich würde die Methode gerne verwenden, weil die Methode laut Autor unabhängig von der Kodierung der Daten im Stream ist.
Ich würde Abstand von diesem Autor nehmen, denn er hat wohl von informationstechnischen Dingen (und von der Java-API!) nicht wirklich Ahnung. Informationen aus Daten unabhängig von ihrer Kodierung zu extrahieren, kommt dem Versuch gleich, Wörter unabhängig von der ihr zu Grunde liegenden Sprache verstehen zu wollen.

Warum der Speicher nicht ausreicht, ist leicht geklärt: Wie bereits gesagt, werden mindestens 4 Bytes als Header ausgewertet, um das Volumen der Folgedaten zu erfassen. "aaaa" ergibt - abhängig von der Zeichensatzkodierung! - z.B. 0x61616161 (ASCII oder kompatibel). Das macht dann, wenn man diese Bytes als Größenangabe interpretiert, 1633771873 Bytes oder rund 1,52 GiB (Gibibyte) an Speicher, die reserviert werden. Aber selbst dieses Reservieren ist fast immer komplett sinnlos. Was auch immer der Autor da erzählt, ist Müll!

Ark
 
Ok,
du hast mich überzeugt.

Nun bleibt die Frage, wie man die Kodierung eines Streams herausbekommt.
 
0001001 hat gesagt.:
Nun bleibt die Frage, wie man die Kodierung eines Streams herausbekommt.
Gar nicht. Man muss zumindest davon ausgehen, dass es sich um Daten in der erwarteten Kodierung handelt. Ansonsten kann man in einen Haufen von Nullen und Einsen alles hineininterpretieren, was man will.

In deinem Fall solltest du uns z.B. mitteilen, von welcher grundsätzlichen Art Information du ausgehst. Soll dieser Stream reinen Text enthalten? Oder ein Bild? PNG? JPEG? Oder ein Dokument in ODF? PDF? Oder Ton? AU? WAV? Solange du das nicht verrätst, ist dir nicht weiterzuhelfen. 😉

Ark
 
Daran soll es nicht scheitern: 🙂

Konkret mache ich folgendes:

Code:
Process proc = Runtime.getRuntime().exec(new String("cmd"),null);
InputStream inputStream = proc.getInputStream();

Die Ausgabe von cmd kommt ja in dem Stream zurück. Diesen würde ich gerne (mit jener Methode von oben) in ein byte[] auslesen.

Nur welche Kodierung hat ein solcher Stream der von cmd kommt?
 
0001001 hat gesagt.:
Nur welche Kodierung hat ein solcher Stream der von cmd kommt?
Keine bestimmte. Das hängt mal wieder auch davon ab, was du mit den Daten anstellen willst. Vielleicht interpretiert cmd die Bytes als Text mit CP850, vielleicht aber auch als Text mit CP1252. Vielleicht ist es UTF-8. Das würde aber, wie gesagt, nur zutreffen, wenn es um Text geht. Wenn ich aber mir den Inhalt eines JPEG-Bildes ausgeben lasse (unter Linux geht das mit dem Befehl cat, und unter Windows, glaube ich, mit type), ist es eben JPEG. Vielleicht ist es aber dann auch schon mit CP850 interpretiert worden, vielleicht mit CP1252. Vielleicht aber auch gar nichts davon. Vielleicht gibt da jemand eine MP3-Datei aus. Wieder etwas ganz anderes ...

Aber vor allem: was willst du damit dann machen? Als Text anzeigen? Oder als Bild? Oder als Ton ausgeben? Oder in eine Datei schreiben? Fragen über Fragen ...

Ark
 
Naja wenn ich einen Kommandozeileninterpreter wie cmd verwende, dann um mit ihm Text ein- und auszugeben.
Selbst wenn ich mir mit type ein jpg ausgeben lasse:
C:\type Sonnenuntergang.jpg
↑Photoshop 3.0 8BIM♥ÝÝ
↑FX Global Lighting Angle ♦ x8BIM♦↓↕FX Global Altitude ♦ ▲8BIM♥¾♂Print
Flags ☺ 8BIM♦
♫Copyright Flag ☺ 8BIM'►¶Japanese Print Flags
☺ ☻8BIM♥§↨Color Halftone Settings H /ff ☺ lff ♠ ☺ /ff ☺ íÖÜ ♠ ☺
2 ☺ Z ♠ ☺ 5 ☺ - ♠ ☺8BIM♥°↨Color Transfer Settings p         
              ♥Þ                       ♥Þ                       ♥Þ     
URL overrides ♦ 8BIM♦Guides ► ☺ ☻@ ☻@ 8BIM♦▲
Dann besitzt zwar das jpg eine bestimmte Kodierung, aber dadurch dass es auf der Konsole ausgegeben wurde, sollte die Kodierung der Konsole angewandt worden sein.

Was ich sagen will: Ein Stream von der Konsole muss doch eine bestimmte Kodierung (bspw. CP12529) besitzen.

Wie würdest du den Output der Konsole aus dem Stream lesen, wenn du ihn so ausgeben möchtest, wie er auch auf der Konsole aussehen würde?
 
Status
Nicht offen für weitere Antworten.

Zurück
Oben