Подтвердить что ты не робот

Самый быстрый способ пошагового чтения большого файла

Если задан буфер 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. Я что-то упускаю? Ожидается ли это? Есть ли более быстрый способ прочитать файл в кусках буфера?

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

4b9b3361

Ответ 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 ГБ.