Javaでバイト配列を整数に、またはその逆に変換します


139

Javaでバイト配列にデータを格納したい。基本的に、数値ごとに最大2バイトを使用できる数値のみ。

整数を2バイトの長さのバイト配列に、またはその逆に変換する方法を教えてください。私は多くの解決策をグーグルで見つけましたが、それらのほとんどはコードで何が起こるかを説明していません。よくわからないことがたくさんあるので、基本的な説明をお願いします。


4
ビットシフトについてどの程度理解してますか?問題は、バイト配列への変換よりも「ビットシフトは何をするのか」ということです。変換がどのように機能するかを実際に理解したい場合は、
Jon Skeet、2011年

1
(明確にするために、どちらの質問でも構いませんが、本当に回答してほしい質問を明確にしおくことは価値があります。その方がより役立つ回答を得る可能性があります。)
Jon Skeet

さて、私はあなたのポイントを得ました!発言ありがとうございます。私はビットシフトがどのようなものであるかを知っていますが、バイト配列の変換に何が使用されているのかまだ理解していません。
Chris

3
@prekageoとJeff Mercado 2つの回答をありがとう。prekageoはこれがどのように行われるかについての良い説明をしてくれました、素晴らしいリンク!それは私にそれをずっとはっきりさせます。そして、ジェフメルカドスソリューションは私が抱えていた問題を解決しました。
Chris

回答:


230

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 }

2
バイト配列に1つまたは2つの整数しか含まれていない場合、それは高すぎますか?を構築するコストについては不明ByteBufferです。
Meow Cat 2012年

2〜4バイトのチャンクでバイナリデータを処理する頻度はどれくらいですか。本当に?正気な実装は、BUFSIZチャンク(通常4kb)で機能するか、この詳細を隠す他のIOライブラリを使用します。フレームワーク内には、データのバッファでの作業に役立つ専用のライブラリ全体があります。よくある理由(パフォーマンスやその他の重要な操作)なしで一般的な操作を実装すると、自分やコードの他のメンテナに害を及ぼすことになります。これらのバッファは、配列を操作するラッパーにすぎません。
ジェフメルカド

なぜ抽象クラスをインスタンス化できるのですか?

1
@JaveneCPPMcGowanこの回答には直接のインスタンス化はありません。ファクトリメソッドwrapおよびを意味する場合allocate、それらは抽象クラスのインスタンスを返しませんByteBuffer
Marko Topolnik

3バイトストライドのソリューションではありません。我々は得ることができCharShortInt。私は4バイトまでパディングして、そのたびに4番目を破棄できると思いますが、むしろそうしません。
John

128
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ビットの符号なし整数型です。


& 0xFFsは不要だと思います。
Ori Popowski 14年

11
@LeifEricson & 0xFFsは、署名されたバイトをこれらのビットのみが設定された整数に変換するようにJVMに指示するため、が必要であると考えています。そうでない場合、バイト-1(0xFF)はint -1(0xFFFFFFFF)になります。私は間違っている可能性があり、私がそれを傷つけていなくても、物事をより明確にします。
coderforlife 2014

4
&0xFFは確かに必須です。 byte b = 0; b |= 0x88; System.out.println(Integer.toString(b, 16)); //Output: -78 System.out.println(Integer.toString(b & 0xFF, 16)); //Output: 88
HBN

1
@ptntialunrlsd実際にはありません。0xFF()で操作を実行する前に、JVMは最初に先行ビットに従って1を拡張する0を拡張してにキャストします。Javaには符号なしバイトはなく、常に署名されています。byteintbyteintbyte
Nier

2
intをバイト配列から解析するときは、バイト配列のサイズに注意してください。4バイトより大きい場合、ByteBuffer.getInt():のドキュメントによるとReads the next four bytes at this buffer's current position、最初の4バイトのみが解析されますが、これは意図したものではありません。
Bin

56

可変長バイトにBigIntegerを使用することもできます。必要に応じて、long、int、shortのいずれかに変換できます。

new BigInteger(bytes).intValue();

または極性を示すには:

new BigInteger(1, bytes).intValue();

バイトを戻すには:

new BigInteger(bytes).toByteArray()

1
1.8以降intValueExactではありませんintValue
Abhijit Sarkar

5

基本的な実装は次のようになります。

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)は最初の整数などを表します。上記のソースコードは整数をリトルエンディアン形式でエンコードします。


2
/** 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;
    }

0

ビットから読み取る必要があるという要件を持つ誰かが、3ビットのみから読み取る必要があるが、符号付き整数が必要な場合は、以下を使用するとします。

data is of type: java.util.BitSet

new BigInteger(data.toByteArray).intValue() << 32 - 3 >> 32 - 3

マジック番号は、使用しているビット数(バイト3数ではない)に置き換えることができます。


0

多くの場合、グアバには必要なものが揃っています。

バイト配列からintに移動するには:Ints.fromBytesArrayここにドキュメント

intからバイト配列に移動するには:Ints.toByteArrayここにドキュメント


-7

これは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;

これは間違っています。バイト0x01を検討してください。あなたのメソッドは間違っている129を出力します。0x01は整数1を出力する必要があります。128を追加する必要があるのは、parseIntから取得した整数が負の場合のみです。
disklosr 2014年

128ではなく256を追加する必要があることを意味しました。後で編集できませんでした。
disklosr 2014年

他の人に役立つかもしれないので、256を追加するように投稿を変更しました!
apmartin1991、2015

これは多くのキャストを行い、パフォーマンスを低下させる可能性のある新しいオブジェクトを作成します(これをforループで行うと考えてください)。Integer.toString()メソッドで、数値の解析方法に関するヒントを確認してください。
Marcos Vasconcelos、2015年

また、stackoverflowにコードを投稿する場合、ポイントは簡単に理解できるコードを投稿することです。簡単に理解できるコードには、理解可能な識別子が必要です。また、stackoverflowでは、「理解可能」は必然的に英語で意味さます。
Mike Nakis
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.