【发布时间】:2016-04-10 21:36:48
【问题描述】:
当给定一个 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 在做同样事情时的速度大约是 NIO 的 100 倍。我错过了什么吗?这是预期的吗?有没有更快的方法来读取缓冲区块中的文件?
最终,我正在处理一个大文件,我没有内存可以一次读取所有文件。相反,我想以块的形式逐步阅读它,然后用于处理。
【问题讨论】:
-
NIO 不一定更快,只是不同而已。如果
java.io对你来说更快,那么忽略 NIO。 -
没有直接字节缓冲区的 NIO 是没用的(或者至少在 Linux 上是 transferTo,在 Windows 上它是模拟的,因此没用)
-
@skaffman,NIO 在正确使用时(严格)更快,与常规 IO 相比,它确实避免了缓冲区复制。不过,对于新手来说,它并不是很容易使用。
-
我只想指出您的两个 impl 正在做不同的事情。示例中的 NIO 代码正在将字节读取到 ByteBuffer 中,然后您从 ByteBuffer 中的后备字节 [] 中再次 逐一读取它们,而在此期间什么也不做-环形。在 IO 代码中,您将字节读入 byte[] 并且不做其他工作。您的 NIO 代码正在执行 2 倍的读取操作以及数十亿次 get() 调用以获取单个字节值。