Чтение потока двоичного ввода в массив байтов в Java - PullRequest
46 голосов
/ 31 августа 2011

В документации сказано, что не следует использовать метод available() для определения размера InputStream.Как я могу прочитать все содержимое 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

Я мог бы прочитать несколько раз в буфер фиксированного размера, но тогда мне придется объединить данные, которые ячитать в один байтовый массив, что является проблемой для меня.

Ответы [ 6 ]

62 голосов
/ 31 августа 2011

Самый простой подход IMO - использовать Гуава и его ByteStreams класс:

byte[] bytes = ByteStreams.toByteArray(in);

Или для файла:

byte[] bytes = Files.toByteArray(file);

В качестве альтернативы (если вы не хотите использовать Guava), вы можете создать ByteArrayOutputStream, многократно читать в байтовый массив и записывать в ByteArrayOutputStream (что позволяет изменять размер) , затем позвоните ByteArrayOutputStream.toByteArray().

Обратите внимание, что этот подход работает независимо от того, можете ли вы указать длину ввода или нет - если, конечно, у вас достаточно памяти.

55 голосов
/ 31 августа 2011

Если вы читаете из файла, вы можете сделать что-то вроде этого:

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

ОБНОВЛЕНИЕ (31 мая 2014 г.):

Java 7 добавляет некоторые новыефункции в пакете java.nio.file, которые можно использовать, чтобы сделать этот пример на несколько строк короче.См. Метод readAllBytes () в классе java.nio.file.Files .Вот краткий пример:

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 не поддерживал это (или многое из того, что есть в Java 7).

9 голосов
/ 31 августа 2011

Вы можете использовать Apache commons-io для этой задачи:

См. этот метод :

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

Обновление:

Java 7 way:

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

и если это текстовый файл, и вы хотите преобразовать его в строку (при необходимости измените кодировку):

StandardCharsets.UTF_8.decode(ByteBuffer.wrap(bytes)).toString()
5 голосов
/ 31 августа 2011

Вы можете прочитать его по чанкам (byte buffer[] = new byte[2048]) и записать чанки в ByteArrayOutputStream.Из ByteArrayOutputStream вы можете получить содержимое в виде байта [], без необходимости предварительно определять его размер.

5 голосов
/ 31 августа 2011

Я считаю, что длина буфера должна быть указана, так как память конечна, и вы можете исчерпать ее

Пример:

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();
3 голосов
/ 31 августа 2011

Максимальное значение для индекса массива - Integer.MAX_INT - оно составляет около 2 ГБ (2 ^ 31/2 147 483 647). Ваш входной поток может быть больше 2 ГБ, поэтому вы должны обрабатывать данные порциями, извините.

        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 
        }
...