当给出MAX_BUFFER_SIZE的缓冲区,并且文件远远超过它时,如何:
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();
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倍。我错过了什么吗?这是预期的吗?有没有更快的方法来读取缓冲区块中的文件?
最终我正在处理一个大文件,我没有记忆可以一次性阅读。相反,我想以块的形式逐步读取它,然后用于处理。
答案 0 :(得分:22)
如果你想让你的第一个例子更快
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();
对于最大2 GB的文件,这可能需要10 - 20微秒。
答案 1 :(得分: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);
}
这使用的缓冲区大小仅为1 KB,但可以传输无限量的数据。
(如果你的答案详细说明了你在功能层面上的实际目的,我可以进一步改进这个答案以获得更好的答案。)