# 16Bit Integer aus ByteArray im Little Endian Format



## Bimbam (22. Mai 2008)

Hallo,
ich möchte ein Programm erstellen, dass Bytes aus einer Datei ausliest.
Das kriege ich noch hin. Doch ich scheitere daran, dass jeweils 2 Bytes zu einer 16Bit Integerzahl zusammengelegt werden, und das im LittleEndian Format.
Wie geht das am besten?
Vielen Dank!


----------



## SlaterB (22. Mai 2008)

beide Bytes in int umwandeln,
evtl auf den Zahlbereich achten: -128 bis +127 vs 0 bis 255

dann ein int shiften << 8 und den anderen addieren


----------



## Guest (22. Mai 2008)

danke.
das mit dem shiften << habe ich schon öfters gelesen, was genau ist das?
und wieso addieren? ich addiere die Zahlen ja nicht ich hänge ihre Bytes nur aneinander.
Gibt es keine KLase dafür (in .Net z.b. BitConverter). Was ist denn mit der KLasse ByteBuffer,
kann die sowas nicht? Davon habe ich nämlich mal was gelesen ...


----------



## SlaterB (22. Mai 2008)

tja, da hast du mehr gelesen als ich, kann dazu nix sagen 
<< verschiebt die Bits

das Shiften wie das Addieren ist wie im Zehner System:
Zahl 3566
-> Bytes 66 + 35

35 shiften zu 3500

3500
+
66
=3566 wie gewüsncht


----------



## quippy (22. Mai 2008)

Das besser Verfahren statt der Addition ist das binäre OR. Um sauber mit negativen Zahlen arbeiten zu können, ist die Maskierung mit dem binären AND notwendig.

Da Du Litte Endian wünschst (also kleinstes Byte ist zuerst im "Stream"), musst Du wie folgt vorgehen:


```
byte [] yourArray;
int size = yourArray.length>>1; // gleich / 2
int [] resultArray = new int[size];

for (int index=0; i<size; i++)
{
   int index = i<<1;
   resultArray[i] = ((byte)(yourArray[index] & 0xFF)) | (((byte)(yourArray[index+1] & 0xFF))<<8) & 0xFFFF;
   // Signed nachvollziehen:
   if ((resultArray[i] & 0x8000) != 0) resultArray[i] |= 0xFFFF0000;
}
```

Das Zweierkomplement wird hier nachträglich getrickst, da andernfalls keine negativen Zahlen kommen würden.

Was ist Shiften?!
Das mit dem Shiften ist im Zehnersystem auch möglich. Dort kommt es einer Multiplikation/Division mit 10 gleich. 3*10 = 30, 30*10 = 300 und so weiter.
Da das Binärsystem zur Basis zwei ist, ist Shiften mit einer Multiplikation/Division mit 2 gleichzusetzen. Intern werden die Bits allerdings tatsächlich roliert. Das aus der Zahlendarstellung herausfallende Bit kommt dabei in's Carry-Flag, so daß man Überläufe auch erkennen kann.


----------



## Guest (22. Mai 2008)

super danke quippy so werde ich das jetzt mal machen.
nur deinen letzten schritt verstehe ich nicht  :cry: 
warum verknüpfe ich meine zahl noch mal mit 0xFFFF0000 um das vorzeichen rauszukriegen?
dadurch kriege ich doch einfach eine 4 Byte Zahl, die erste 2 Bytes alles Einsen und der Rest ist meine eigentliche Zahl?


----------



## SlaterB (22. Mai 2008)

das passiert ja auch nur bei 0x8000, also wenn das 16. Bit eine 1 ist, was für eine negative Zahl steht,
und damit das dann auch in Java-32-bit-int eine negative Zahl ist müsssen die Einsen da rein:


```
public class Test
{
    public static void main(String[] args)
        throws Exception
    {
        int k = (int)Math.pow(2, 15);
        System.out.println(k + " - " + Integer.toBinaryString(k));

        if ((k & 0x8000) != 0)
        {
            k |= 0xFFFF0000;
        }
        System.out.println(k + " - " + Integer.toBinaryString(k));
    }


}
```


----------



## Guest (22. Mai 2008)

Schau dir das mal an.
	
	
	
	





```
FileInputStream is = new FileInputStream(file);
FileChannel channel = is.getChannel();
MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
buffer.order(ByteOrder.LITTLE_ENDIAN);

short value = buffer.getShort();
...
```


----------



## Guest (22. Mai 2008)

achso ok danke also bei ner 32 Bit Zahl zählen die ersten 16 bits praktisch als -wert richtig? ist das nur bei 32 bit werten so?
und @ gast was ist das für ein beispiel? da versteh ich ja mal gar nix -.-


----------



## SlaterB (22. Mai 2008)

> zählen die ersten 16 bits praktisch als -wert richtig?

nicht immer, das wäre ja Verschwendung, 

nur für eh nur die unteren 16 Bits belegt sind, dann kann sicher sein, dass die obigen immer 0 sind,
oder alle 1 wenn die Zahl negativ ist


----------



## Guest (22. Mai 2008)

Anonymous hat gesagt.:
			
		

> achso ok danke also bei ner 32 Bit Zahl zählen die ersten 16 bits praktisch als -wert richtig? ist das nur bei 32 bit werten so?
> und @ gast was ist das für ein beispiel? da versteh ich ja mal gar nix -.-


Damit kanst du die ganze Datei, unter brücksichtigung von Byte-Order, komplett auslesen, statt die Bytes "von Hand"
zu Integern zusammen zu kleistern. Java bietet mit der NIO API die nötige Funkionalität, warum diese nicht auch 
verwenden.
Die Pufferung ist sauschnell. Ich kann damit z.B. 100 TIFF - Header innerhalb von 150ms auslesen und darin sämtliche
IFD-Einträge auswerten. Darauf basierend ein Index mit Offsets der Thumbnails, EXIFs und IPTC-Daten aufbauen, um 
diese bei Bedarf schnell laden zu können.


----------



## Gast (22. Mai 2008)

häh, und wie kann ich dann eine 8 Bit lange Zahl negativ darstellen? und woher weiß java die zahl nicht einfach 32Bits lang ist anstatt der negtiven darstellung?


----------



## SlaterB (23. Mai 2008)

> häh, und wie kann ich dann eine 8 Bit lange Zahl negativ darstellen? 

nach dem gleichen System, dann sind die ersten 24 Bits eine 1

>  und woher weiß java die zahl nicht einfach 32Bits lang ist anstatt der negtiven darstellung?

was hat die negative Darstellung mit der Länge der Zahl zu tun bzw. wo siehst du da einen Konflikt?
das ist ein konsistentes System,
nur wenn man die Zahl wie in diesem Thread aus Bytes zusammenbaut ist die Negation noch nicht korrekt,
deshalb ja der Code von quippy:
> if ((resultArray_ & 0x8000) != 0) resultArray |= 0xFFFF0000;_


----------



## Gast (25. Mai 2008)

hm jo danke ich probiers erstmal mit methode 1.
es klappt auch, nur komischerweise erhalte ich teilweise andere ergebnisse als mit c# -.-
denn die eingelesen bits sind teilweise unterschiedlich.
Ich lese meine Bits so ein:
import java.io.*;

public class fileReader
{
	public byte[] einlesen(String datei)
	{
		try
		{
		BufferedReader reader = new BufferedReader(new FileReader(datei));
		byte line;

		byte[] binhalt = new byte[(int)new File(datei).length()];
		int c;
		int i = 0;
		while ((c = reader.read()) != -1)
		{
			binhalt_ = (byte)c;
			i++;
		}


		return binhalt;
		}
		catch (IOException e)
		{
			byte[] fehler = ("Datei nicht gefunden.").getBytes();
			return (fehler);
		}

	}
}

binhalt wird dann mit slaters methode ins little endian format konvertiert. wo liegt der fehler?_


----------



## semi (25. Mai 2008)

Lese zuerst wozu der BufferedReader geeignet ist. Nimm doch einfach den MappedByteBuffer, wie im Beispiel oben gezeigt.


----------



## Gast (25. Mai 2008)

hm ja gut ich machs mal mit dem mappedbytebuffer
nur wollte erstmal das "manuell" probieren, die bits mit dem bufferedreader einlesen( das müsste doch gehn oder?) und dann selber shiften und so ...


----------



## semi (25. Mai 2008)

Ich zitiere mal einen Ausschnitt des ersten Satzes in der API-Doku zu BufferedReader


> Reads text from a *character-input stream*...


Merkst du was?  Du hast eine Binärdatei, kannst daher diesen Reader nicht verwenden. 
Wenn du es von Hand machen möchtest, mach's so, wie 'SlaterB' vorgeschlagen hat. Ansonsten mit NIO, 
wie in meinem Beispiel (ich war mal wieder als Dauergast nicht eingelogt) gezeigt.


----------



## Gast (25. Mai 2008)

achso ist das stimmt danke!


----------

