Ich möchte einige Daten in Byte-Arrays in Java speichern. Grundsätzlich nur Zahlen, die bis zu 2 Bytes pro Zahl aufnehmen können.
Ich würde gerne wissen, wie ich eine Ganzzahl in ein 2 Byte langes Byte-Array umwandeln kann und umgekehrt. Ich habe viele Lösungen gefunden, die googeln, aber die meisten erklären nicht, was im Code passiert. Es gibt viele Sachen, die ich nicht wirklich verstehe, daher würde ich mich über eine grundlegende Erklärung freuen.
Verwenden Sie die Klassen im Namespace Java.nio
, insbesondere die ByteBuffer
. Es kann die ganze Arbeit für Sie erledigen.
byte[] arr = { 0x00, 0x01 };
ByteBuffer wrapped = ByteBuffer.wrap(arr); // big-endian by default
short num = wrapped.getShort(); // 1
ByteBuffer dbuf = ByteBuffer.allocate(2);
dbuf.putShort(num);
byte[] bytes = dbuf.array(); // { 0, 1 }
byte[] toByteArray(int value) {
return ByteBuffer.allocate(4).putInt(value).array();
}
byte[] toByteArray(int value) {
return new byte[] {
(byte)(value >> 24),
(byte)(value >> 16),
(byte)(value >> 8),
(byte)value };
}
int fromByteArray(byte[] bytes) {
return ByteBuffer.wrap(bytes).getInt();
}
// packing an array of 4 bytes to an int, big endian
int fromByteArray(byte[] bytes) {
return bytes[0] << 24 | (bytes[1] & 0xFF) << 16 | (bytes[2] & 0xFF) << 8 | (bytes[3] & 0xFF);
}
Beim Packen von signierten Bytes in ein int muss jedes Byte ausgeblendet werden, da es aufgrund der arithmetischen Heraufstufungsregel (beschrieben in JLS, Conversions und Promotions) auf 32 Bit (statt auf Null erweitert) vorzeichenerweitert wird.
Es gibt ein interessantes Puzzle, das in Java Puzzlers ("Eine große Freude in jedem Byte") von Joshua Bloch und Neal Gafter beschrieben wird. Wenn Sie einen Bytewert mit einem int-Wert vergleichen, wird das Byte zu einem int-Wert erweitert, und dieser Wert wird dann mit dem anderen int verglichen
byte[] bytes = (…)
if (bytes[0] == 0xFF) {
// dead code, bytes[0] is in the range [-128,127] and thus never equal to 255
}
Beachten Sie, dass alle numerischen Typen in Java signiert sind, mit der Ausnahme, dass char ein vorzeichenloser 16-Bit-Integer-Typ ist.
Sie können BigInteger auch für Bytes mit variabler Länge verwenden. Sie können es in lang, int oder kurz umwandeln, je nachdem, was Ihren Bedürfnissen entspricht.
new BigInteger(bytes).intValue();
oder um Polarität zu bezeichnen:
new BigInteger(1, bytes).intValue();
Um Bytes zurück zu bekommen, einfach:
new BigInteger(bytes).toByteArray()
Eine grundlegende Implementierung würde etwa so aussehen:
public class Test {
public static void main(String[] args) {
int[] input = new int[] { 0x1234, 0x5678, 0x9abc };
byte[] output = new byte[input.length * 2];
for (int i = 0, j = 0; i < input.length; i++, j+=2) {
output[j] = (byte)(input[i] & 0xff);
output[j+1] = (byte)((input[i] >> 8) & 0xff);
}
for (int i = 0; i < output.length; i++)
System.out.format("%02x\n",output[i]);
}
}
Um die Dinge zu verstehen, können Sie diesen Artikel WP lesen: http://en.wikipedia.org/wiki/Endianness
Der obige Quellcode gibt 34 12 78 56 bc 9a
aus. Die ersten 2 Bytes (34 12
) stellen die erste Ganzzahl usw. dar. Der obige Quellcode kodiert Ganzzahlen im Little Endian-Format.
/** length should be less than 4 (for int) **/
public long byteToInt(byte[] bytes, int length) {
int val = 0;
if(length>4) throw new RuntimeException("Too big to fit in int");
for (int i = 0; i < length; i++) {
val=val<<8;
val=val|(bytes[i] & 0xFF);
}
return val;
}
Jemand mit einer Anforderung, bei der er aus Bits lesen muss, lässt Sie sagen, dass Sie nur aus 3 Bits lesen müssen, aber Sie benötigen eine vorzeichenbehaftete Ganzzahl.
data is of type: Java.util.BitSet
new BigInteger(data.toByteArray).intValue() << 32 - 3 >> 32 - 3
Die magische Zahl 3
kann durch die Anzahl der Bits (nicht Bytes) ersetzt werden, die Sie verwenden.