web-dev-qa-db-ja.com

Javaのバイナリ入力ストリームをシングルバイト配列に読み込む

ドキュメント は、InputStreamのサイズを決定するためにavailable()メソッドを使用してはならないと述べています。 InputStreamのコンテンツ全体をバイト配列に読み込むにはどうすればよいですか?

InputStream in; //assuming already present
byte[] data = new byte[in.available()];
in.read(data);//now data is filled with the whole content of the InputStream

固定サイズのバッファーに複数回読み込むことができますが、読み込んだデータを単一のバイト配列に結合する必要があり、これは私にとって問題です。

46
Qiang Li

IMOの最も簡単なアプローチは、 Guava およびその ByteStreams クラスを使用することです。

_byte[] bytes = ByteStreams.toByteArray(in);
_

またはファイルの場合:

_byte[] bytes = Files.toByteArray(file);
_

あるいは(グアバを使用したくない場合) ByteArrayOutputStream を作成し、バイト配列を繰り返し読み取り、ByteArrayOutputStream(書き込みサイズ変更を処理する)、 ByteArrayOutputStream.toByteArray() を呼び出します。

このアプローチは、入力の長さを伝えることができるかどうかに関係なく機能することに注意してください-もちろん、十分なメモリがあると仮定します。

62
Jon Skeet

ここでの回答は、ファイルの長さがInteger.MAX_VALUE(2147483647)以下であることを前提としていることに注意してください。

ファイルから読み込む場合、次のようなことができます。

    File file = new File("myFile");
    byte[] fileData = new byte[(int) file.length()];
    DataInputStream dis = new DataInputStream(new FileInputStream(file));
    dis.readFully(fileData);
    dis.close();

更新(2014年5月31日):

Java 7は、この例を数行短くするために使用できるJava.nio.fileパッケージにいくつかの新機能を追加します。 Java.nio.file.Files クラスの readAllBytes() メソッドを参照してください。短い例を次に示します。

import Java.nio.file.FileSystems;
import Java.nio.file.Files;
import Java.nio.file.Path;

// ...
        Path p = FileSystems.getDefault().getPath("", "myFile");
        byte [] fileData = Files.readAllBytes(p);

Androidは、これを Apiレベル26 (8.0.0、Oreo)以降でサポートしています。

56
James K Polk

このタスクには、Apache commons-io を使用できます。

このメソッド を参照してください:

public static byte[] readFileToByteArray(File file) throws IOException

更新:

Java 7方法:

byte[] bytes = Files.readAllBytes(Paths.get(filename));

そして、それがテキストファイルであり、それを文字列に変換したい場合(必要に応じてエンコードを変更します):

StandardCharsets.UTF_8.decode(ByteBuffer.wrap(bytes)).toString()
9
Andrey

メモリは有限であり、使い果たしてしまう可能性があるため、バッファ長を指定する必要があると思います

例:

InputStream in = new FileInputStream(strFileName);
    long length = fileFileName.length();

    if (length > Integer.MAX_VALUE) {
        throw new IOException("File is too large!");
    }

    byte[] bytes = new byte[(int) length];

    int offset = 0;
    int numRead = 0;

    while (offset < bytes.length && (numRead = in.read(bytes, offset, bytes.length - offset)) >= 0) {
        offset += numRead;
    }

    if (offset < bytes.length) {
        throw new IOException("Could not completely read file " + fileFileName.getName());
    }

    in.close();
5
JAM

チャンク(byte buffer[] = new byte[2048])チャンクをByteArrayOutputStreamに書き込みます。 ByteArrayOutputStreamから、内容をbyte []として取得できます。事前にサイズを決定する必要はありません。

5
SJuan76

配列インデックスの最大値はInteger.MAX_INT-約2Gb(2 ^ 31/2 147 483 647)です。入力ストリームは2Gbより大きくなる可能性があるため、データをチャンクで処理する必要があります。

        InputStream is;
        final byte[] buffer = new byte[512 * 1024 * 1024]; // 512Mb
        while(true) {
            final int read = is.read(buffer);
            if ( read < 0 ) {
                break;
            }
            // do processing 
        }
3
ya_pulser