【问题标题】:Is it possible to create an in-memory File object in Java?是否可以在 Java 中创建内存中的 File 对象?
【发布时间】:2014-03-10 17:46:05
【问题描述】:

我现在正在进行的优化项目之一广泛使用EPANet。我们反复调用 EPANet 中的两种模拟方法来了解水如何流经配水网络。

HydraulicSim 是我们使用的类之一。查看重载的simulate 方法:

public void simulate(File hyd) throws ENException {
    ...
}

public void simulate(OutputStream out) throws ENException, IOException {
    ...
}

public void simulate(DataOutput out) throws ENException, IOException {
    ...
}

我们使用的另一个类是QualitySim。在这里,我们还使用了重载的simulate 方法:

public void simulate(File hydFile, File qualFile) throws IOException, ENException {
    ...
}

void simulate(File hydFile, OutputStream out) throws IOException, ENException {
    ...
}

这是我们目前正在做的事情:

  1. 创建两个File 对象hydFilequalFile
  2. 拨打HydraulicSim.simulatehydFile
  3. hydFilequalFile 上致电QualitySim.simulate
  4. 删除文件。

问题是我们必须这样做很多次。对于一个大问题,我们可以这样做几十万甚至几百万次。您可以想象重复创建/写入/删除这些文件会导致减速。

所以我的问题是:我是否可以创建这些文件,使它们仅驻留在内存中而从不接触磁盘?每个文件都非常小(我说的是几百字节),因此将它们放入内存中不会有问题;我只需要弄清楚如何。我四处搜索并没有真正找到太多,除了MappedByteBuffer,但我不确定如何,或者是否有可能从该类创建File

欢迎任何建议!

【问题讨论】:

  • 向 EPANet 团队提交问题可能是值得的。模拟方法都简单地使用 File 对象来获取输入和输出流。如果他们提供了一个将流作为参数的QualitySim.simulate 方法(它们对输出流而不是输入流执行此操作),您可以绕过FS。或者只是分叉并自己做。
  • 可以使用ByteArrayOutputStream和ByteArrayInputStream,但必须预先分配足够大的字节数组。
  • 一定要使用文件吗?由于您已经有一些使用 Streams 的函数,因此您可以改用 ByteArrayOutputStream 和 ByteArrayInputStream。
  • @LeonardBrünings QualitySim 类不提供接受输入参数 (hydFile) 流的方法。
  • @MikeB 是的,我看到了,但是正如您已经提到的那样,实施更改将是微不足道的。因此,我只需添加该方法并发出拉取请求以供他们包含它。

标签: java


【解决方案1】:

最直接的解决方案是在此处挂载 ramdisk 并存储文件。然后你不需要触摸你的代码,文件访问会很快:-)

Linux

# mkfs -q /dev/ram1 8192
# mkdir -p /ramcache
# mount /dev/ram1 /ramcache

MacOS

  1. http://osxdaily.com/2007/03/23/create-a-ram-disk-in-mac-os-x/

Windows

  1. http://support.microsoft.com/kb/257405
  2. http://www.softperfect.com/products/ramdisk/

【讨论】:

【解决方案2】:

您可以使用 Memory mapped file。 Java在FileChannel类中提供API,例如

channel.map(FileChannel.MapMode.READ_WRITE, start, PAGE_SIZE)

public abstract MappedByteBuffer map(FileChannel.MapMode mode,
                   long position,
                   long size)
                              throws IOException

Java 仅提供 32 位指针来操作 MappedByteBuffer,但您可以使用切片来映射超过 2GB 的文件,例如

private void memoryMapFile(File file) throws FileNotFoundException, IOException {
        RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
        FileChannel channel = randomAccessFile.getChannel();
        List<MappedByteBuffer> buffers = new ArrayList<MappedByteBuffer>();
        long size = channel.size();
        long start = 0;
        int index = 0;
        for (index = 0; start + PAGE_SIZE <= size; index++) {       
            buffers.add(index, channel.map(FileChannel.MapMode.READ_WRITE, start, PAGE_SIZE));
            start = (index+1)*PAGE_SIZE;
        }
        if(start+PAGE_SIZE > size){
            buffers.add(index, channel.map(FileChannel.MapMode.READ_WRITE, start, PAGE_SIZE));
        }
    }

【讨论】:

  • 您如何获得接受 File 对象并自己构造流以使用该文件的方法?在调用其他函数之前只调用memoryMapFile(File file) 就足够了吗?
  • 谢谢。您的示例更清楚地显示了如何使用MappedByteBuffer。不过,我想问题仍然是我必须将File 对象传递给这些方法。我认为修改 EPANet 代码是我最终需要做的。
【解决方案3】:

向 EPANet 团队提交问题可能是值得的。模拟方法都简单地使用 File 对象来获取输入和输出流。如果他们提供了一个QualitySim.simulate 将流作为参数的方法(它们为输出流而不是输入流),您可以绕过FS。或者只是 fork 并自己做。

【讨论】:

【解决方案4】:

这可能有点矫枉过正,但 Java 7 提供了一种创建自定义文件系统的方法:

http://docs.oracle.com/javase/7/docs/technotes/guides/io/fsp/filesystemprovider.html

您可以使用它在内存中创建自己的由 Map 或 byte[]s 支持的文件系统。但是,文件系统似乎使用了新的 Path 对象,而不是 File(尽管有一些方法可以与文件相互转换)

不过对于你正在尝试做的事情来说可能有点过头了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-07-15
    • 1970-01-01
    • 1970-01-01
    • 2017-09-21
    • 2013-05-24
    • 2010-10-13
    • 2011-01-15
    相关资源
    最近更新 更多