Java中的内存映射文件

时间:2009-06-21 04:27:23

标签: java memory-mapping

我一直在尝试编写一些非常快速的Java代码,它必须执行大量的I / O操作。我正在使用一个返回ByteBuffer的内存映射文件:

public static ByteBuffer byteBufferForFile(String fname){
    FileChannel vectorChannel;
    ByteBuffer vector;
    try {
        vectorChannel = new FileInputStream(fname).getChannel();
    } catch (FileNotFoundException e1) {
        e1.printStackTrace();
        return null;
    }
    try {
        vector = vectorChannel.map(MapMode.READ_ONLY,0,vectorChannel.size());
    } catch (IOException e) {
        e.printStackTrace();
        return null;
    }
    return vector;
}

我遇到的问题是ByteBuffer .array()方法(应返回byte []数组)不适用于只读文件。我想编写我的代码,以便它可以与内存中构造的内存缓冲区和从磁盘读取的缓冲区一起使用。但是我不想把我的所有缓冲区都包装成ByteBuffer.wrap()函数,因为我担心这会减慢速度。所以我一直在编写所有内容的两个版本,一个采用byte [],另一个采用ByteBuffer。

我应该把所有东西都包好吗?或者我应该双重写一切?

4 个答案:

答案 0 :(得分:10)

有没有人真正检查内存映射创建的ByteBuffers是否支持首先调用.array(),而不管readonly / readwrite是什么?

据我所知,据我所知,答案是ByteBuffer通过byte[]返回直接ByteBuffer.array()数组的能力受ByteBuffer.hbbyte[])的影响,该MappedByteBuffer总是设置为null创建{{1}}时。

对我来说哪种方式很糟糕,因为我希望做一些类似于作者想要做的事情。

答案 1 :(得分:5)

不重新发明轮子总是好的。 Apache提供了一个用于执行I / O操作的漂亮库。看看http://commons.apache.org/io/description.html

这是它所服务的场景。假设你有一些数据 宁愿留在记忆中,但你不知道提前有多少数据 那里将是。如果有太多,你想把它写到磁盘上 而不是占用内存,但你不想写到磁盘,直到你 需要,因为磁盘很慢并且是需要跟踪的资源 清理。

所以你创建一个临时缓冲区并开始写入。如果/当你 达到你想要记忆的门槛,你需要 创建一个文件,写出缓冲区中该文件的内容,然后全部写入 后续数据到文件而不是缓冲区。

这就是 DeferredOutputStream 为您所做的事情。它隐藏了所有的混乱 在切换点附近。你需要做的就是创造 首先是延迟流,配置阈值,然后只是 写下你心中的内容。

编辑:我刚刚使用谷歌进行了一次小型重新搜索,发现此链接: http://lists.apple.com/archives/java-dev/2004/Apr/msg00086.html (Lightning快速文件读/写)。非常令人印象深刻。

答案 2 :(得分:4)

包装byte []不会减慢速度......不会有任何巨大的阵列副本或其他小的性能弊端。来自JavaDocs:java.nio.ByteBuffer .wrap()

  

将字节数组包装到缓冲区中。

     

新缓冲区将由给定的字节数组支持; 即,   对缓冲区的修改将导致   要修改的数组和副   反之亦然。新缓冲区的容量和   limit将是array.length,它的   位置将为零,并且它的标记   将是未定义的。它的后备阵列   将是给定的数组及其数组   offset将为零。

答案 3 :(得分:1)

使用ByteBuffer.wrap()功能不会带来很高的负担。它分配一个简单的对象并初始化一些整数。因此,如果您需要使用只读文件,那么根据ByteBuffer编写算法是最好的选择。