8

我一直在尝试编写一些必须执行大量 I/O 的非常快速的 Java 代码。我正在使用一个返回 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

4 回答 4

10

有没有人真正检查是否ByteBuffers由内存映射支持.array()首先调用创建,而不管只读/读写?

据我所知,答案是否定的。AByteBuffer返回直接byte[]数组 via的能力由( )ByteBuffer.array()的存在决定,在创建a 时它始终设置为 null 。ByteBuffer.hbbyte[]MappedByteBuffer

这对我来说有点糟糕,因为我希望做一些类似于问题作者想做的事情。

于 2009-07-15T20:27:25.610 回答
7

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

这是它所服务的场景。假设您有一些您希望保留在内存中的数据,但您不提前知道会有多少数据。如果有太多,您想将其写入磁盘而不是占用内存,但您不想在需要之前写入磁盘,因为磁盘很慢并且是需要跟踪以进行清理的资源。

因此,您创建一个临时缓冲区并开始写入该缓冲区。如果/当您达到要保留在内存中的阈值时,您需要创建一个文件,将缓冲区中的内容写入该文件,并将所有后续数据写入文件而不是缓冲区。

这就是DeferredOutputStream为您所做的。它隐藏了切换点的所有混乱。您需要做的就是首先创建延迟流,配置阈值,然后写出您心中的内容。

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

于 2009-06-21T06:31:23.490 回答
4

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

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

新缓冲区将由给定的字节数组支持;也就是说,对缓冲区的修改将导致数组被修改,反之亦然。新缓冲区的容量和限制将为 array.length,其位置为零,其标记未定义。它的后备数组将是给定的数组,并且它的数组偏移量将为零。

于 2009-06-21T06:08:00.073 回答
1

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

于 2009-06-21T06:04:44.200 回答