私はこのようなバイナリファイルを読んでいます:
_InputStream in = new FileInputStream( file );
byte[] buffer = new byte[1024];
while( ( in.read(buffer ) > -1 ) {
int a = // ???
}
_
最大4バイトを読み取り、それらからint値を作成するために何をしたいのですが、それを行う方法がわかりません。
一度に4バイトを取得し、1バイトの操作(>> << >>&FFなど)を実行して新しいintを作成する必要があるように感じます
このイディオムは何ですか?
[〜#〜] edit [〜#〜]
これはもう少し複雑であることがわかりました(説明するために)
私がやろうとしているのは、ファイルを読んで(ASCII、バイナリ、それは問題ではないかもしれません)、それが持っているかもしれない整数を抽出することです。
たとえば、バイナリコンテンツ(ベース2内)を想定します。
_00000000 00000000 00000000 00000001
00000000 00000000 00000000 00000010
_
整数表現は_1
_、_2
_である必要があります。 :-/最初の32ビットは1、残りの32ビットは2。
_11111111 11111111 11111111 11111111
_
-1になります
そして
_01111111 11111111 11111111 11111111
_
Integer.MAX_VALUE ( 2147483647 )
になります
ByteBufferにはこの機能があり、リトルエンディアンとビッグエンディアンの両方の整数を扱うことができます。
この例を考えてみましょう:
// read the file into a byte array
File file = new File("file.bin");
FileInputStream fis = new FileInputStream(file);
byte [] arr = new byte[(int)file.length()];
fis.read(arr);
// create a byte buffer and wrap the array
ByteBuffer bb = ByteBuffer.wrap(arr);
// if the file uses little endian as apposed to network
// (big endian, Java's native) format,
// then set the byte order of the ByteBuffer
if(use_little_endian)
bb.order(ByteOrder.LITTLE_ENDIAN);
// read your integers using ByteBuffer's getInt().
// four bytes converted into an integer!
System.out.println(bb.getInt());
お役に立てれば。
次のような関数に配置する必要があります。
_public static int toInt(byte[] bytes, int offset) {
int ret = 0;
for (int i=0; i<4 && i+offset<bytes.length; i++) {
ret <<= 8;
ret |= (int)bytes[i] & 0xFF;
}
return ret;
}
_
例:
_byte[] bytes = new byte[]{-2, -4, -8, -16};
System.out.println(Integer.toBinaryString(toInt(bytes, 0)));
_
出力:
_11111110111111001111100011110000
_
これにより、バイトが不足し、負のバイト値が正しく処理されます。
私はこれを行うための標準機能を知りません。
考慮すべき問題:
エンディアンネス:異なるCPUアーキテクチャは、intを構成するバイトを異なる順序で配置します。最初にバイト配列をどのように作成するかによっては、これについて心配する必要があります。そして
バッファリング:一度に1024バイトを取得し、要素1022でシーケンスを開始すると、4バイトを取得する前にバッファの終わりにヒットします。おそらく自動的にバッファリングされるバッファリングされた入力ストリームの何らかの形式を使用する方がよいでしょう。そうすれば、readByte()
を繰り返し使用でき、それ以外は心配する必要はありません。
トレーリングバッファ:入力の終わりは、ソースによって不均一なバイト数(特に4の倍数ではない)になる場合があります。ただし、最初から入力を作成し、4の倍数であることが「保証」されている(または少なくとも前提条件である)場合は、それを気にする必要はありません。
バッファリングのポイントについてさらに詳しく説明するには、 BufferedInputStream
を検討してください。
_InputStream in = new BufferedInputStream(new FileInputStream(file), 1024);
_
これでInputStream
があります自動的に一度に1024バイトをバッファリングします。これは扱いにくいです。このようにすると、一度に4バイトを快適に読み取ることができ、I/Oが多すぎることを心配する必要はありません。
次に、 DataInputStream
を使用することもできます。
_InputStream in = new DataInputStream(new BufferedInputStream(
new FileInputStream(file), 1024));
byte b = in.readByte();
_
あるいは:
_int i = in.readInt();
_
int
sの構築についてはまったく心配しません。
dataInputStream.readInt()の実装方法を確認してください。
int ch1 = in.read();
int ch2 = in.read();
int ch3 = in.read();
int ch4 = in.read();
if ((ch1 | ch2 | ch3 | ch4) < 0)
throw new EOFException();
return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
最も簡単な方法は次のとおりです。
RandomAccessFile in = new RandomAccessFile("filename", "r");
int i = in.readInt();
- または -
DataInputStream in = new DataInputStream(new BufferedInputStream(
new FileInputStream("filename")));
int i = in.readInt();
次のようなものを試してください:
a = buffer[3];
a = a*256 + buffer[2];
a = a*256 + buffer[1];
a = a*256 + buffer[0];
これは、最下位バイトが最初に来ると仮定しています。最上位バイトが最初に来る場合、インデックスを交換する必要があります(0から3に移動します)。
基本的に、追加する各バイトに対して、最初にa 256(左への8ビットのシフトに等しい)を乗算してから、新しいバイトを追加します。
可変長バイトにBigIntegerを使用することもできます。必要に応じて、Long、Integer、またはShortに変換できます。
new BigInteger(bytes).intValue();
または極性を示すため:
new BigInteger(1, bytes).intValue();
for (int i = 0; i < buffer.length; i++)
{
a = (a << 8) | buffer[i];
if (i % 3 == 0)
{
//a is ready
a = 0;
}
}
4バイト配列を整数に変換する:
//Explictly declaring anInt=-4, byte-by-byte
byte[] anInt = {(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xfc}; // Equals -4
//And now you have a 4-byte array with an integer equaling -4...
//Converting back to integer from 4-bytes...
result = (int) ( anInt[0]<<24 | ( (anInt[1]<<24)>>>8 ) | ( (anInt[2]<<24)>>>16) | ( (anInt[3]<<24)>>>24) );
次のコードは、array
(a byte[]
)index
の位置にあり、int
を返します。 Java 10と私が思い描いた他のいくつかのバリエーションに関する他の回答からのコードのほとんどを試しました。
このコードは最小のCPU時間を使用しましたが、Java 10のJITが割り当てを削除するまでByteBuffer
を割り当てます。
int result;
result = ByteBuffer.
wrap(array).
getInt(index);
このコードは、何も割り当てない最高のパフォーマンスのコードです。残念ながら、上記のコードと比較して56%長いCPU時間を消費します。
int result;
short data0, data1, data2, data3;
data0 = (short) (array[index++] & 0x00FF);
data1 = (short) (array[index++] & 0x00FF);
data2 = (short) (array[index++] & 0x00FF);
data3 = (short) (array[index++] & 0x00FF);
result = (data0 << 24) | (data1 << 16) | (data2 << 8) | data3;
符号なし4バイトを整数として読み取るには、符号付きビットが符号なし数値の一部と見なされるため、長い変数を使用する必要があります。
long result = (((bytes[0] << 8 & bytes[1]) << 8 & bytes[2]) << 8) & bytes[3];
result = result & 0xFFFFFFFF;
これはうまく機能していることがテストされています