增量读取大文件的最快方法

Jam*_*sev 19 java file-io nio

当给出MAX_BUFFER_SIZE的缓冲区和远远超过它的文件时,如何:

  1. 以MAX_BUFFER_SIZE块的形式读取文件?
  2. 尽可能快地做到

我尝试过使用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();
Run Code Online (Sandbox Code Playgroud)

和常规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();
Run Code Online (Sandbox Code Playgroud)

事实证明,与NIO做同样的事情,常规IO的速度要快100倍.我错过了什么吗?这是预期的吗?有没有更快的方法来读取缓冲区块中的文件?

最终,我正在处理一个大文件,我没有记忆可以一次阅读.相反,我想以块的形式逐步读取它,然后用于处理.

Pet*_*rey 23

如果你想让你的第一个例子更快

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();
Run Code Online (Sandbox Code Playgroud)

如果你想要它更快.

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();
Run Code Online (Sandbox Code Playgroud)

对于最大2 GB的文件,这可能需要10 - 20微秒.

  • 刚查看源代码,发现关闭文件通道并没有关闭随机访问文件,但反过来,所以一定要关闭RandomAccessFile :) (3认同)
  • 不要忘记关闭RandomAccessFile,因为它是资源泄漏. (2认同)

zie*_*mer 20

假设您需要立即将整个文件读入内存(正如您当前所做的那样),读取较小的块或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);
}
Run Code Online (Sandbox Code Playgroud)

这使用的缓冲区大小仅为1 KB,但可以传输无限量的数据.

(如果你扩展你的答案,详细说明你在功能层面上的实际目的,我可以进一步改进这个以获得更好的答案.)