Как я могу прочитать определенное количество байтов в буфер? - PullRequest
1 голос
/ 19 ноября 2011

Следующая проблема: у меня большой текстовый файл с каждой строкой, содержащей 13 байтов. Я не хочу читать файл построчно обычным способом, используя InputStream. Я пытаюсь использовать каналы NIO и MappedByteBuffers для лучшей производительности и ограниченных ресурсов.

Так вот что я делаю до сих пор:

RandomAccessFile data = new RandomAccessFile("the_file.txt", "rw");
FileChannel channel = data.getChannel();
MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, capacity);

Здесь емкость - это n * 13, чтобы убедиться, что в буфер помещаются только целые строки. Но это не работает! Я заполняю буфер так:

int bytesRead = channel.read(buffer);

Но это еще не полный буфер! bytesRead не равно емкость , а в моем случае еще хуже bytesRead% 13 не равно ноль , что означает, что оно не содержит целых линии, в конце концов что-то отрезано. Как я могу прочитать определенное количество байтов в буфер? В моем случае мне нужно ровно n * 13 байтов, чтобы исходные строки не разбивались ...

Ответы [ 3 ]

2 голосов
/ 19 ноября 2011

Беглый взгляд на документацию раскрывает правду о методе read.

Операция чтения может не заполнить буфер, и на самом деле она не можетчитать любые байты вообще.

Из этого должно быть совершенно ясно, что нельзя предполагать, что вызов read заполнит буфер.Чтобы достичь этого, вам нужно создать цикл, проверяющий, сколько осталось прочитать:

while(buffer.remaining() > 0) channel.read(buffer);

В мощном API-интерфейсе Java-потока все это обрабатывается автоматически.

Я предлагаю использоватьпростой BufferedReader , а затем измерить производительность.Затем вы можете принять более взвешенное решение о повторной попытке с классами NIO.Вы будете удивлены производительностью потоковых классов.Это решение также даст вам код, который легче поддерживать и читать.

1 голос
/ 12 февраля 2012

Если вы используете MappedByteBuffer, то вы также можете отобразить весь файл за один раз. Java и система виртуальных машин ОС будут считывать данные с диска в память , как требуется . Он не будет считывать весь файл в память сразу, если он действительно не будет маленьким. Затем вы можете сосредоточиться на своем коде, просто получая доступ к диапазону байтов, которые вас интересуют для каждого цикла / чтения.

Ваш более подробный, комплексный подход (и соответствующие ответы здесь) больше подходит для традиционного ByteBuffer, в котором вы явно контролируете то, что читается в память с диска.

1 голос
/ 19 ноября 2011

если у вас есть bytesRead%13!=0, тогда сопоставьте новый буфер с channel.map(FileChannel.MapMode.READ_WRITE, (bytesRead/13)*13, capacity); и не обрабатывайте последние bytesRead%13 каждого буфера

...