Javaでバイト配列にデータを格納したい。基本的に、数値ごとに最大2バイトを使用できる数値のみ。
整数を2バイトの長さのバイト配列に、またはその逆に変換する方法を教えてください。私は多くの解決策をグーグルで見つけましたが、それらのほとんどはコードで何が起こるかを説明していません。よくわからないことがたくさんあるので、基本的な説明をお願いします。
Javaでバイト配列にデータを格納したい。基本的に、数値ごとに最大2バイトを使用できる数値のみ。
整数を2バイトの長さのバイト配列に、またはその逆に変換する方法を教えてください。私は多くの解決策をグーグルで見つけましたが、それらのほとんどはコードで何が起こるかを説明していません。よくわからないことがたくさんあるので、基本的な説明をお願いします。
回答:
java.nio
名前空間にあるクラス、特にを使用しByteBuffer
ます。それはあなたのためにすべての仕事をすることができます。
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 }
ByteBuffer
です。
wrap
およびを意味する場合allocate
、それらは抽象クラスのインスタンスを返しませんByteBuffer
。
Char
、Short
、Int
。私は4バイトまでパディングして、そのたびに4番目を破棄できると思いますが、むしろそうしません。
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, minimal parentheses
// operator precedence: <<, &, |
// when operators of equal precedence (here bitwise OR) appear in the same expression, they are evaluated from left to right
int fromByteArray(byte[] bytes) {
return bytes[0] << 24 | (bytes[1] & 0xFF) << 16 | (bytes[2] & 0xFF) << 8 | (bytes[3] & 0xFF);
}
// packing an array of 4 bytes to an int, big endian, clean code
int fromByteArray(byte[] bytes) {
return ((bytes[0] & 0xFF) << 24) |
((bytes[1] & 0xFF) << 16) |
((bytes[2] & 0xFF) << 8 ) |
((bytes[3] & 0xFF) << 0 );
}
符号付きバイトをintにパックするとき、算術昇格規則(JLS、変換および昇格で説明)により、各バイトは(ゼロ拡張ではなく)32ビットに符号拡張されるため、マスクする必要があります。
Joshua BlochとNeal GafterによるJava Puzzlers( "A Big Delight in Every Byte")で説明されているこれに関連する興味深いパズルがあります。バイト値をint値と比較する場合、バイトはintに符号拡張され、この値は他のintと比較されます
byte[] bytes = (…)
if (bytes[0] == 0xFF) {
// dead code, bytes[0] is in the range [-128,127] and thus never equal to 255
}
すべての数値型はJavaで署名されていますが、charは16ビットの符号なし整数型です。
& 0xFF
sは不要だと思います。
& 0xFF
sは、署名されたバイトをこれらのビットのみが設定された整数に変換するようにJVMに指示するため、が必要であると考えています。そうでない場合、バイト-1(0xFF)はint -1(0xFFFFFFFF)になります。私は間違っている可能性があり、私がそれを傷つけていなくても、物事をより明確にします。
byte b = 0; b |= 0x88; System.out.println(Integer.toString(b, 16)); //Output: -78 System.out.println(Integer.toString(b & 0xFF, 16)); //Output: 88
byte
int
byte
int
byte
ByteBuffer.getInt()
:のドキュメントによるとReads the next four bytes at this buffer's current position
、最初の4バイトのみが解析されますが、これは意図したものではありません。
可変長バイトにBigIntegerを使用することもできます。必要に応じて、long、int、shortのいずれかに変換できます。
new BigInteger(bytes).intValue();
または極性を示すには:
new BigInteger(1, bytes).intValue();
バイトを戻すには:
new BigInteger(bytes).toByteArray()
intValueExact
ではありませんintValue
基本的な実装は次のようになります。
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]);
}
}
事柄を理解するために、このWP記事を読むことができます:http : //en.wikipedia.org/wiki/Endianness
上記のソースコードが出力されます34 12 78 56 bc 9a
。最初の2バイト(34 12
)は最初の整数などを表します。上記のソースコードは整数をリトルエンディアン形式でエンコードします。
これはintにキャストするのに最適なモードだと思います
public int ByteToint(Byte B){
String comb;
int out=0;
comb=B+"";
salida= Integer.parseInt(comb);
out=out+128;
return out;
}
最初のバイトを文字列に変換
comb=B+"";
次のステップはintに変換することです
out= Integer.parseInt(comb);
しかし、バイトはこの理由で-128から127の範囲にあります。私は範囲0から255を使用する方が良いと思います。これを行う必要があるだけです。
out=out+256;