Чтение двоичного входного потока в один байтовый массив в Java
В документации говорится, что не следует использовать метод 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
Я мог читать несколько раз в буфер фиксированного размера, но тогда мне придется объединить данные, которые я прочитал, в один байт-массив, что для меня проблема.
Ответы
Ответ 1
Самый простой подход IMO - использовать Guava и его класс ByteStreams
:
byte[] bytes = ByteStreams.toByteArray(in);
Или для файла:
byte[] bytes = Files.toByteArray(file);
Альтернативно (если вы не хотите использовать Guava), вы можете создать ByteArrayOutputStream
и многократно считывать в байтовый массив и записывать в ByteArrayOutputStream
(позволяя изменять размер дескриптора), а затем вызывать ByteArrayOutputStream.toByteArray()
.
Обратите внимание, что этот подход работает независимо от того, можете ли вы указать длину вашего ввода или нет - если у вас достаточно памяти, конечно.
Ответ 2
Помните, что в приведенных здесь ответах предполагается, что длина файла меньше или равна 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();
ОБНОВЛЕНИЕ (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 уровня 26 (8.0.0, Oreo).
Ответ 3
Вы можете использовать Apache commons-io для этой задачи:
Обратитесь к этот метод:
public static byte[] readFileToByteArray(File file) throws IOException
Update:
Java 7:
byte[] bytes = Files.readAllBytes(Paths.get(filename));
и если это текстовый файл, и вы хотите преобразовать его в String (при необходимости измените кодировку):
StandardCharsets.UTF_8.decode(ByteBuffer.wrap(bytes)).toString()
Ответ 4
Я считаю, что длина буфера должна быть указана, так как память конечна, и вы можете ее исчерпать
Пример:
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
Вы можете прочитать его кусками (byte buffer[] = new byte[2048]
) и записать куски в ByteArrayOutputStream. Из ByteArrayOutputStream вы можете получить содержимое в виде байта [], не задумываясь заранее определить его размер.
Ответ 6
Максимальное значение для индекса массива - 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
}