2011-11-14 12 views
4

数値をバイト配列に変換する必要があります。たとえば、バイト配列に長いを変換するために、私はこの方法を持っている:このJava ByteBufferの動作についての説明はありますか?

public static byte[] longToBytes(long l) { 
    ByteBuffer buff = ByteBuffer.allocate(8); 

    buff.order(ByteOrder.BIG_ENDIAN); 

    buff.putLong(l); 

    return buff.array(); 
} 

それはとても簡単だ - それを保持できる配列を割り当て、長いを取り、そこにそれを投げます。 lの値が何であるかにかかわらず、私は8バイトの配列を取得し、処理して意図したとおりに使用することができます。私の場合は、カスタムバイナリ形式を作成し、それをネットワーク経由で送信しています。

このメソッドを773450364の値で呼び出すと、配列[0 0 0 0 46 25 -22 124]が返されます。

public static Long bytesToLong(byte[] aBytes, int start) { 
    byte[] b = new byte[8]; 

    b[0] = aBytes[start + 0]; 
    b[1] = aBytes[start + 1]; 
    b[2] = aBytes[start + 2]; 
    b[3] = aBytes[start + 3]; 
    b[4] = aBytes[start + 4]; 
    b[5] = aBytes[start + 5]; 
    b[6] = aBytes[start + 6]; 
    b[7] = aBytes[start + 7]; 

    ByteBuffer buf = ByteBuffer.wrap(b); 
return buf.getLong(); 
} 

Iがバックこの方法に他の方法からの配列を渡すと、私は773450364を取得し、正しい:私はまた戻ってその数値にバイト配列を変換するコードを有します。

ここで、このアレイをTCP経由で別のJavaクライアントに送信します。 java.io.InputStream.read()メソッドのドキュメントでは、ストリームの終わりに達して-1が返されない限り、intの値が0から255の間で返されると記載されています。しかし、それを使ってバイト配列を生成すると、受信側で負の値を取得し続けます。私はこれがオーバーフロー(255の値はJavaバイトに収まらないので、バイト配列に入れるとオーバーフローして負になります)と関係していると思われます。

これは私の問題につながります。負の数の存在は私に関係している。今、アプリケーションのJava側を開発しています。バイトは-128〜127の間です。もう1つのエンドポイントは、C、C++、Python、Java、C#などがあります。私はいくつかのバイト配列の負の値の存在が処理にどのように影響するかについてはわかりません。 この動作を文書化する以外に、このシステムで作業している自分や将来の開発者、特にJavaで書かれていないエンドポイントで、これを簡単にするにはどうすればよいですか?

+0

'longToBytes'と同じように' getLong() 'を呼び出す前に、ByteBufferのエンディアンを' bytesToLong'メソッドで設定するべきではありませんか?本当にあなたの質問には関係ありません、ちょうど不思議... –

+0

@G_H私はそれを調べてテストする必要があります。私は実際にこれらの方法のどちらも自分で書いておらず、テストケースは欠けています。それを指摘してくれてありがとう。 –

答えて

6

byte Javaは、8ビットtwo's complement形式で表されます。 intが128〜255の範囲にあり、それをbyteにキャストすると、負の値(-1〜-128の間)を持つbyteになります。

バイトを読み取った後、それをbyteにキャストする前に-1 であることを確認する必要があります。このメソッドがbyteではなくintを返す理由は、ストリームの末尾がbyteに変換される前にチェックできるようにするためです。

もう1つの理由:bytesToLongの方法でaBytesアレイをコピーする理由は何ですか?あなたはかなりその方法を簡素化し、unncessaryコピーを保存することができます

public static Long bytesToLong(byte[] aBytes, int start) { 
    return ByteBuffer.wrap(aBytes, start, 8).order(ByteOrder.BIG_ENDIAN).getLong(); 
} 
1

どちらもあなたの送信側と受信側のエンドポイントは、現在、Javaで実装されています。送信側でOutputStream、受信側でInputStreamを使用していると考えられます。基本的なソケット実装の詳細をしばらく信じているとすれば、ソケットを介して送信されたバイトは、宛先にまったく同じになるとみなされます。

OutputStreamに何かをダンプすると、Javaのレベルで実際に何が起こりますか?the JavaDoc for a method writing a byte arrayをチェックすると、ストリーム上でバイトが送信されていることがわかります。そこには大事なことはない。しかし、method taking an int as argumentのドキュメントをチェックすると、このintが実際に書き出される仕組みがわかります。下位8ビットはストリームを介してバイトとして送信され、上位24ビット(intはJavaでの32ビット表現)は単に無視されます。

受信側にあります。あなたはInputStreamを持っています。 one of the methods reading directly into a byte arrayを使用しない限り、intが与えられます。 Like the doc saysの場合、intは0〜255の値をとり、ストリームの終わりに達した場合は-1を返します。これは重要なビットです。一方では、1バイトの可能なすべてのビットパターンをInputStreamから読み取ることができます。しかし、読み込みがもはや意味のある値を返すことができなくなったときを検出する何らかの方法も必要です。そのため、このメソッドはバイトの代わりにintを返します。-1の値はストリームの終わりに達したことを示すフラグです。 -1以外のものがあれば、興味のあるのはそれらの下位8ビットだけです。これらはいずれのビットパターンでも構いませんので、小数値の範囲は-128から127までです。 intの代わりにint型のバイト配列に直接読み込むと、 "トリミング"が実行されます。だから、あなたはそれらの負の値を見るつもりだということは意味があります。つまり、Javaが符号付き小数点としてのバイトを表す方法のために、それらは負の値に過ぎません。重要なのは実際のビットパターンだけです。あなたはそれが一般的なのInputStream

1255に255または1000に値0を表すことが気にすべてのために一度に1つのバイトを使用してループは、このような見るつもりです読み:

InputStream ips = ...; 
int read = 0; 
while((read = ips.read()) != -1) { 
    byte b = (byte)read; 
    //b will now have a bit pattern ranging from 0x00 to 0xff in hex, or -128 to 127 in two-complement signed representation 
} 

を、以下を実行すると、 (Javaの7 int型のリテラルを使用しています)は、照明されます。

public class Main { 

    public static void main(String[] args) { 

     final int i1 = Ox00_00_00_fe; 
     final int i1 = Ox80_00_00_fe; 

     final byte b1 = (byte)i1; 
     final byte b2 = (byte)i2; 

     System.out.println(i1); 
     System.out.println(i2); 

     System.out.println(b1); 
     System.out.println(b2); 

     final int what = Ox12_34_56_fe; 
     final byte the_f = (byte)what; 

     System.out.println(what); 
     System.out.println(the_f); 

    } 

} 

としては、int型からbyteにキャストすることは、単純に最下位8ビット以外のものを捨てます、このことから明らかであろう。したがって、intは正または負の数になる可能性があり、バイト値には関係しません。最後の8ビットのみ。

短いストーリー:InputStreamから正しいバイト値を取得しています。ここで実際に心配しておきたいのは、クライアント側がプログラミング言語で書かれていて、どのプラットフォームでも実行できるのであれば、受信したバイトが何を意味しているのかを文書で十分に明らかにする必要があります。エンコードされます。特定のエンディアンでByteBufferputLongメソッドを使用して、エンコードがJavaで行われていることを明確にします。そうしたときだけ、それらのバイトをどのように解釈するかを確実にするための情報(Java仕様と組み合わせて)を得ます。

0

すべてのデータがビッグエンディアンであれば、このすべての問題を解決し、DataOutputStreamを使用できます。それはあなたが必要とするすべてを持っています。

+0

残念ながら、それはすべてのビッグエンディアンではありません。 –

関連する問題