Java中的文件流

Ale*_*aev 8 java streaming random-access

我目前正在使用JOGL(Java OpenGL绑定)开发3D图形应用程序.简而言之,我有一个巨大的横向二进制文件.由于它的大小,我必须在运行时流式传输地形块.因此,我们明确地看到随机访问问题.我已经完成了第一个(和脏:))实现(也许它是多线程的),我正在使用一个愚蠢的方法......这是它的初始化:

dataInputStream = new DataInputStream(new BufferedInputStream(fileInputStream,4 * 1024);
dataInputStream.mark(dataInputStream.available());
Run Code Online (Sandbox Code Playgroud)

当我需要读取(流)特殊块(我已经在文件中知道它的"偏移量")时,我正在执行以下操作(对我感到羞耻:)):

dataInputStream.reset();
dataInputStream.skipBytes(offset);
dataInputStream.read(whatever I need...);
Run Code Online (Sandbox Code Playgroud)

因为我没有经验,这是我能想到的第一件事:)所以,直到现在我已经阅读了3篇有用且非常有趣的文章(我建议你阅读它们,或许如果你对这个主题感兴趣的话)

  1. 字节缓冲区和非堆内存 - 格雷戈里先生似乎在Java NIO中识字.

  2. Java技巧:如何快速阅读文件 [http://nadeausoftware.com/articles/2008/02/java_tip_how_read_files_quickly] - 这是一个有趣的基准.

  3. 文章:调优Java I/O性能 [http://java.sun.com/developer/technicalArticles/Programming/PerfTuning/] - 简单的Sun建议,但请向下滚动并查看那里的"随机访问"部分; 它们显示了RandomAccessFile(RAF)的简单实现,具有自缓冲改进.

格雷戈里先生在他的文章末尾提供了几个*.java文件.其中之一是FileChannel + ByteBuffer + Mapping(FBM)和RAF之间的基准测试.他说,与英国皇家空军相比,他在使用FBM时注意到了4倍的加速.我在以下条件下运行此基准:

  1. 偏移量(例如访问位置)是随机生成的(在文件范围内,例如0 - file.length());
  2. 文件大小为220MB;
  3. 1 000 000次访问(75%读取和25%写入)

结果令人震惊:

英国皇家空军大约28秒! FBM约0.2秒!

但是,他在这个基准测试中实现RAF并没有自我缓冲(第3篇文章讲述了一个),所以我猜这是调用的"RandomAccessFile.seek"方法,他们如此努力地降低了性能.

好的,现在经过我所学到的所有这些事情,有1个问题和1个困境:)

问题:当我们使用"FileChannel.map"映射文件时,Java是否将整个文件内容复制到MappedByteBuffer中?或者它只是模仿它?如果它复制,那么使用FBM方法不适合我的情况,是吗?

困境:取决于你对这个问题的答案......

  1. 如果映射复制文件,那么我似乎只有2个可能的解决方案:RAF +自缓冲(第3篇文章中的那个)或者使用FileChannel中的位置(不使用映射)...哪一个会会更好?

  2. 如果映射不复制文件,那么我有3个选项:前两个和FBM本身.

编辑:这是另外一个问题.你们有些人说,映射不会将文件复制到MappedByteBuffer中.那么,为什么我不能映射1GB文件呢,我收到"无法映射"的消息......

PS我想通过建议得到满意的答案,因为我无法在互联网上找到关于此主题的一致信息.

谢谢 :)

som*_*guy 3

不,数据没有被缓冲。MappedByteBuffer 使用指针引用数据。换句话说,数据没有被复制,它只是被映射到物理内存中。如果您还没有查看API 文档,请参阅。

内存映射文件是一段虚拟内存,它被分配了与文件或类文件资源的某些部分的直接逐字节关联。该资源通常是物理上存在于磁盘上的文件,但也可以是设备、共享内存对象或操作系统可以通过文件描述符引用的其他资源。一旦存在,文件和内存空间之间的这种相关性允许应用程序将映射部分视为主内存。

资料来源:维基百科

如果您要经常读取数据,那么至少缓存其中一些数据是个好主意。