Byte Stream dekodieren

continue

Aktives Mitglied
Hallo,

In meiner Applikation empfange ich einen Byte Stream via InpuStream.
Die Bytes sind dabei speziell kodiert:

Code:
A L D1 D2 ...DN CS

A... Anfang eines data frames (immer 0x20)
L... Länge, gibt an wieviel bytes in diesem data frame folgen
D1-DN... Datenbytes
CS... Ein Byte checksumme

Der Datenstream sieht als z.b. so aus:
Code:
0x20 0x05 0x01 0x02 0xD1 0xA1 0xAF
0x20 0x05 0x12 0x03 0x02 0x3A 0xF2
...
...
Nun habe ich mich gefragt wie ich das am besten (effizient) dekodieren kann.
Ich habe mir gedacht einen BufferedInputStream zu verwenden ist sicher nich verkehrt. Ich stelle mir das dann so vor (Semipseudocode):





PHP:
BufferedInputStream bufIS = new BufferedInputStream(mInStream);
while (true ) {
    byte startFrame = bufIS.read();
    if(startFrame == 0x20) {
        int length = bufIS.read();
    
        byte dataframe[] = new bye[length];
        for (int i = 0; i<length i++) {
            dateframe[i] = bufIS.read();
        }
    
    if(verifyChecksum(bufIS.read()) postEvent(dataframe);
    }
}

Wäre das so okay (üblich)?
Zuerst wollte ich die Methode public int read(byte[] b,int off,int len) und ein Bufferarray verwenden aber da hätte ich das problem dass read nie zuverlässig "len" Anzahl an Bytes zurückliefert.
Ist meine oben beschriebene Vorgehensweise halbwegs effizient oder geht es schneller/performanter oder einfacher?

Grüße
 
Zuletzt bearbeitet:

Tobse

Top Contributor
Das ist schonmal ganz gut. Bei der geringen Menge an Bytes würde ich aber auf den BufferedStream verzichten.
Auch fäält mir auf: In deinem Beispiel stehen zwar 5 Bytes als Länge drin; abzüglich der Checksumme sinds aber nur 4.

Dein Code wird so wahrscheinlich funktionieren. Du prüfst leider nicht wieviele Bytes tatsächlich gelesen wurden daher musst du mit einer IOException/AIOOB-Exception rechnen.

Als Beispiel: Ich hätte das so gelößt:
Java:
InputStream in = /** get input stream */;

int ci = in.read();
byte[] buffer = new byte[255]; // buffer, initialisiert mit maximaler größe
while (ci == 0x20)
{
	ci = in.read();
	if (ci == -1)
	{
		throw new IOException("Unexpected EOF");
	}
	short len = (short) (0xFF & ci); // längen-byte als unsigned behandeln um bis zu 255 bytes zu erlauben
	
	int actuallyRead = in.read(buffer, 0, len);
	
	if (actuallyRead < len)
	{
		throw new IOException("Unexpected EOF in Data-Frame ???: wanted to read "
			+ len + " bytes, only " + actuallyRead + " found.");
	}
	
	byte checksum = (byte) (0xFF & in.read());
	if (!checkChecksum(buffer, 0, len, checksum))
	{
		throw new IOExcetpion("Invalid checksum in Data-Frame ???");
	}
	
	// trigger event
	
	ci = in.read();
}
abstract boolean checkChecksum(byte[] byteBuffer, int offset, int len, byte checksum);
Da hier der Buffer nur einmal initialisiert wird, sparst du dir den RAM und die Zeit dafür. Ausserdem ließt mein Code über rad(byte[], int, int) und nicht in einer Schleife via read() was effizienter sein kann, je nachdem Welcher Stream da zugrunde liegt.
Das letzte, winzige Detail ist, dassd durch die Verwendung von InputStream (im gegensatz zu BufferedInputStream) verlässliche Werte von read()/read(byte[], int, int) geliefert werden und man so detailiertere Fehlerbeschreibungen in die EOF-Exceptions bekommt.
 
Zuletzt bearbeitet:

continue

Aktives Mitglied
Hallo & Danke für die Antwort.
Das letzte, winzige Detail ist, dassd durch die Verwendung von InputStream (im gegensatz zu BufferedInputStream) verlässliche Werte von read()/read(byte[], int, int) geliefert werden und man so detailiertere Fehlerbeschreibungen in die EOF-Exceptions bekommt.

Bist du dir da sicher? Aus der Doku von InputStream entnehme ich für read(byte[],int,int):

Reads up to len bytes of data from the input stream into an array of bytes. An attempt is made to read as many as len bytes, but a smaller number may be read. The number of bytes actually read is returned as an integer.

d.h. is können auch weniger bytes gelesen werden was bei deinem Codebeispiel dazu führen würde dass eine IOException geworfen werden würde oder?
 

Tobse

Top Contributor
d.h. is können auch weniger bytes gelesen werden was bei deinem Codebeispiel dazu führen würde dass eine IOException geworfen werden würde oder?

Richtig, genau darum geht es ja.
Java:
	int actuallyRead = in.read(buffer, 0, len);
 
	if (actuallyRead < len)
	{
		throw new IOException("Unexpected EOF in Data-Frame ???: wanted to read "
			+ len + " bytes, only " + actuallyRead + " found.");
	}

Können vom Stream nicht so viele Bytes gelesen werden, wie in der längenangabe steht, dann wirt dein Code eine ArrayIndexOutOfBoundException ohne Fehlermeldung. Meiner wirft eine IOException mit der Fehlermeldung, dass nicht so viele Bytes gelesen werden kontnen wie nötig.
Und weil das die Bessere Fehlerbeschreibung ist, macht es das Debuggen/Testen einfacher.
 

Thallius

Top Contributor
Und wenn man es richtig machen will, dann schaut man vorher wie groß die Datei eigentlich ist und wenn einem die Länge nicht passt, dann bringt man einen Fehler. Ansonsten liest man genau soviele Bytes ein wie die Datei lang ist.

Ist das jetzt soviel schwerer als mit Exceptions um sich zu werfen?

Gruß

Claus
 

Tobse

Top Contributor
Und wenn man es richtig machen will, dann schaut man vorher wie groß die Datei eigentlich ist und wenn einem die Länge nicht passt, dann bringt man einen Fehler. Ansonsten liest man genau soviele Bytes ein wie die Datei lang ist.

Ist das jetzt soviel schwerer als mit Exceptions um sich zu werfen?

Bitte was? Du schreibst doch sonst so gute Antworten. Natürlich kann ich die Länge der Datei vorher prüfen - aber ob der Inhalt semantisch richtig ist weiss ich doch vorher nicht? Und was, wenn die Festplatte nen schluckauf kriegt? Dann reisst auch der Stream ab.
Mal gnaz davon abgesehen - wenn ich die Methode versatil einsetzen möchte, dann sollte sie von jeder Art InputStream lesen können. Und bei einem Socket hast du exakt das gleiche Problem wenn z.B. das WLAN abreisst.
Zu guter letzt: Bei einer Datei, die 20-30MB groß ist wäre es ja noch zu verantworten, dass man sie Roh in den Ram lädt. Aber was soll denn bitte ein VLC-Player bei einem 10GB großen HD-Film machen?
 
Zuletzt bearbeitet:

Thallius

Top Contributor
Bitte was? Du schreibst doch sonst so gute Antworten. Natürlich kann ich die Länge der Datei vorher prüfen - aber ob der Inhalt semantisch richtig ist weiss ich doch vorher nicht? Und was, wenn die Festplatte nen schluckauf kriegt? Dann reisst auch der Stream ab.
Mal gnaz davon abgesehen - wenn ich die Methode versatil einsetzen möchte, dann sollte sie von jeder Art InputStream lesen können. Und bei einem Socket hast du exakt das gleiche Problem wenn z.B. das WLAN abreisst.
Zu guter letzt: Bei einer Datei, die 20-30MB groß ist wäre es ja noch zu verantworten, dass man sie Roh in den Ram lädt. Aber was soll denn bitte ein VLC-Player bei einem 10GB großen HD-Film machen?

Wo schreibe ich das er sie auf einmal komplett ins RAM lesen soll? Ich sage nur er soll vorher die Länge ermitteln und dann solange lesen bis er die Länge hat. Nur dann kann er sicher sein, dass das Lesen erfolgreich war. Wenn dabei Fehler auftreten, dann sind das wirklich Ausnahmen die man auch mit einer Exception abfagen sollte.

Aber einfach eine Datei solange zu lesen bis man eine IOException bekommt und dann davon auszugehen, dass das dann EOF war, ist ja wohl totaler Humbug. Denn dann denkst du auch du hast die Datei korrekt gelesen wenn Du deinen WLAN Discinnect hast oder eine Festplatte mit Schluckauf.

Gruß

Claus
 

Tobse

Top Contributor
Sorry, ich hatte dashier
Ansonsten liest man genau soviele Bytes ein wie die Datei lang ist.
als "komplett in den RAM lesen" verstanden.

Ja, du hast recht, meine Methode wirft eine IOException am EOF, das ist nicht optimal. Das Problem ist doch aber, dass die Menge an Bytes in der Datei selbst steht. Und durch die bloße Größe der Datei lässt sich die Datenintegrität nicht prüfen.
Daher also ein Verbesserungsvorschlag:
Java:
InputStream in = /** get input stream */;

int ci = in.read();
byte[] buffer = new byte[255]; // buffer, initialisiert mit maximaler größe
while (ci != -1)
{
	if (ci != 0x20)
	{
		throw new IOException("Expected Frame-Start (0x20) but found " + ci);
	}
	
	ci = in.read();
	if (ci == -1)
	{
		throw new IOException("Unexpected EOF");
	}
	
	short len = (short) (0xFF & ci); // längen-byte als unsigned behandeln um bis zu 255 bytes zu erlauben
	
	int actuallyRead = in.read(buffer, 0, len);
	
	if (actuallyRead < len)
	{
		throw new IOException("Unexpected EOF in Data-Frame ???: wanted to read "
			+ len + " bytes, only " + actuallyRead + " found.");
	}
	
	byte checksum = (byte) (0xFF & in.read());
	if (!checkChecksum(buffer, 0, len, checksum))
	{
		throw new IOExcetpion("Invalid checksum in Data-Frame ???");
	}
	
	// trigger event

	ci = in.read();
}
 
Zuletzt bearbeitet:
Ähnliche Java Themen
  Titel Forum Antworten Datum
J byte[] auf Stream schreiben Netzwerkprogrammierung 2
x46 Byte-Array per for-Schleife schicken Netzwerkprogrammierung 1
x46 byte[] über BufferedReader auslesen Netzwerkprogrammierung 18
D Socket Gute Idee?: File als byte[] per ObjectIOStream übertragen Netzwerkprogrammierung 3
M TCP Verbindung Byte-weise lesen? Netzwerkprogrammierung 5
W Socket Byte Array senden Netzwerkprogrammierung 2
M Byte Array kommt nicht an Netzwerkprogrammierung 0
N Paket-Analysieren Byte-Streams Netzwerkprogrammierung 12
K Socket byte Schleife beendet nicht Netzwerkprogrammierung 9
K Byte für Byte aus InputStream lesen Netzwerkprogrammierung 5
B Socket Byte-array Komprimieren Netzwerkprogrammierung 3
J Probleme bei RSA mit byte[] bei Versand über RMI Netzwerkprogrammierung 2
N String als byte Array über Socket versenden Netzwerkprogrammierung 8
T Outputstream Byte-Array senden Netzwerkprogrammierung 2
Q NullPointExeption beim Versuch byte[] zu senden/writen Netzwerkprogrammierung 3
E RTP Packet lesen - Byte Problem 0xFFFFFF80 statt 0x80 Netzwerkprogrammierung 7
V Zuweisen einer InetAddress mit einem byte Netzwerkprogrammierung 5
D Byte-Zähler des Netzwerkinterface auslesen Netzwerkprogrammierung 2
T Kommunikation auf Byte-Ebene zw. C und Java via Socket Netzwerkprogrammierung 12
B HEX String zu einem Byte Array ? *verzweiflung* :( Netzwerkprogrammierung 16
H Byte-Codierung bei Socket-Verbindung ändern Netzwerkprogrammierung 8
8 Socket Streams nur mit Byte? Netzwerkprogrammierung 2
G binärwert aus 2 byte auslesen Netzwerkprogrammierung 7
O Ip-String in byte[]-Array umwandeln? Netzwerkprogrammierung 3
D Daten per Server- Client nur als byte verschicken? Netzwerkprogrammierung 3
O JAVA hängt bei Dateikopie über LAN ein Byte an!!! ARGH Netzwerkprogrammierung 3
L Server-Socket liest Input-Stream nicht Netzwerkprogrammierung 5
E Socket Werte mit DataInput- und Output- Stream übergeben Netzwerkprogrammierung 1
T MP3 Dateien Stream Netzwerkprogrammierung 3
G Video aus RTSP Stream speichern Netzwerkprogrammierung 8
B Socket BufferedReader.readLine() beenden ohne den Stream zu closen Netzwerkprogrammierung 7
A versch. Daten im Stream erkennen Netzwerkprogrammierung 2
E stream speichern Netzwerkprogrammierung 5
S Dateitransfer - kein end of stream Netzwerkprogrammierung 5
M RTP Stream überprüfen... Netzwerkprogrammierung 4
K ein Thread pro Stream Netzwerkprogrammierung 2
M Objekt über Object-Stream, empfange "alte" Daten Netzwerkprogrammierung 2
B Pdf Stream von Servlet mit itext Netzwerkprogrammierung 12
K End of stream, BufferedInputStream Netzwerkprogrammierung 4
A Icecast / SHOUTcast MP3 Stream / icy-metaint Netzwerkprogrammierung 3
Kr0e Simpler HTTP Stream server Test Netzwerkprogrammierung 3
H String Array durch einen Stream schicken. Netzwerkprogrammierung 4
lacyuu Warum empfängt mein Stream keinen Input? Netzwerkprogrammierung 4
lordcarlos Erstes TCP programm - output stream problem Netzwerkprogrammierung 2
dayaftereh Bester Stream für ein Spiel? Netzwerkprogrammierung 15
N Socket Stream Schicken Netzwerkprogrammierung 13
N Socket Stream in String Netzwerkprogrammierung 4
M Bytes aus Stream lesen Netzwerkprogrammierung 3
M ich habe ein stream problem Netzwerkprogrammierung 7
S Schnellster Stream Netzwerkprogrammierung 20
V Mehrere Streams durch einen Stream senden Netzwerkprogrammierung 14
W Was für ein Stream soll ich verwenden? Netzwerkprogrammierung 8
F Stream wird als Char übertragen. Char -> in String umwand Netzwerkprogrammierung 5
A java.io.StreamCorruptedException: invalid stream header Netzwerkprogrammierung 2
C invalid stream header Netzwerkprogrammierung 2
T Stream de-multiplexen Netzwerkprogrammierung 2
J gzip Stream weiterleiten Netzwerkprogrammierung 3
m@nu Ende von Stream bei HTTP-Request Netzwerkprogrammierung 3
C Problem mit Object-Stream Netzwerkprogrammierung 3
N TCP Stream auslesen Netzwerkprogrammierung 7
André B. Stream Bridge? Netzwerkprogrammierung 2
P Verschiedene Daten über einen Stream Netzwerkprogrammierung 4
T Musik-Stream: Server sendet die Datei zu schnell ? Netzwerkprogrammierung 3
N InternetRadio-Stream umleiten Netzwerkprogrammierung 2
G Writer oder Stream bei Socket? Netzwerkprogrammierung 2
G Datei über HTTP Stream senden Netzwerkprogrammierung 4

Ähnliche Java Themen

Neue Themen


Oben