Самый быстрый способ пошагового чтения большого файла
Если задан буфер MAX_BUFFER_SIZE и файл, который намного превышает его, как это сделать:
- Прочитайте файл в блоках MAX_BUFFER_SIZE?
- Сделайте это как можно быстрее
Я попытался использовать NIO
RandomAccessFile aFile = new RandomAccessFile(fileName, "r");
FileChannel inChannel = aFile.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(CAPARICY);
int bytesRead = inChannel.read(buffer);
buffer.flip();
while (buffer.hasRemaining()) {
buffer.get();
}
buffer.clear();
bytesRead = inChannel.read(buffer);
aFile.close();
И правильный IO
InputStream in = new FileInputStream(fileName);
long length = fileName.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 " + fileName);
}
in.close();
Оказывается, что обычный IO примерно в 100 раз быстрее, делая то же самое, что и NIO. Я что-то упускаю? Ожидается ли это? Есть ли более быстрый способ прочитать файл в кусках буфера?
В конечном счете я работаю с большим файлом, у меня нет памяти, чтобы читать все сразу. Вместо этого я бы хотел прочитать его поэтапно в блоках, которые затем будут использоваться для обработки.
Ответы
Ответ 1
Предполагая, что вам необходимо сразу же прочитать весь файл в памяти (как вы сейчас делаете), ни чтение небольших фрагментов, ни NIO не помогут вам здесь.
Фактически, вы, вероятно, лучше всего читаете большие куски, которые ваш обычный IO-код автоматически делает для вас.
Ваш код NIO в настоящее время медленнее, потому что вы читаете только один байт за раз (используя buffer.get();
).
Если вы хотите обработать куски - например, переключение между потоками - вот стандартный способ сделать это без NIO:
InputStream is = ...;
OutputStream os = ...;
byte buffer[] = new byte[1024];
int read;
while((read = is.read(buffer)) != -1){
os.write(buffer, 0, read);
}
В этом случае размер буфера составляет всего 1 КБ, но может передавать неограниченное количество данных.
(Если вы продлеваете свой ответ с подробностями того, что вы на самом деле хотите сделать на функциональном уровне, я мог бы улучшить это для лучшего ответа.)
Ответ 2
Если вы хотите сделать свой первый пример быстрее
FileChannel inChannel = new FileInputStream(fileName).getChannel();
ByteBuffer buffer = ByteBuffer.allocateDirect(CAPACITY);
while(inChannel.read(buffer) > 0)
buffer.clear(); // do something with the data and clear/compact it.
inChannel.close();
Если вы хотите, чтобы он был еще быстрее.
FileChannel inChannel = new RandomAccessFile(fileName, "r").getChannel();
MappedByteBuffer buffer = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());
// access the buffer as you wish.
inChannel.close();
Это может занять от 10 до 20 микросекунд для файлов размером до 2 ГБ.