可以创建一个java RAM磁盘来与java.io.*API一起使用吗?

可以创建一个java RAM磁盘来与java.io.*API一起使用吗?,java,unit-testing,ramdisk,Java,Unit Testing,Ramdisk,我使用的是一个第三方库,它基本上创建了一个输出目录,其中包含不同类型的文件和子目录。我希望能够编写单元测试来确认输出是否正确 我希望能够将lib与RAM磁盘一起使用,这样库就不会以任何方式接触实际的磁盘板。这样做的目的是使测试能够非常快速地运行和清理(丢弃RAM磁盘?) 我可以选择的两个最突出的选项是和。前者对我没有用处,因为我希望使用java.io.*API而不是Commons VFS类透明地工作。后者没有解决这个问题,因为我必须适应JDK 6(它应该是JDK 7的一部分),而且我不知道它是否

我使用的是一个第三方库,它基本上创建了一个输出目录,其中包含不同类型的文件和子目录。我希望能够编写单元测试来确认输出是否正确

我希望能够将lib与RAM磁盘一起使用,这样库就不会以任何方式接触实际的磁盘板。这样做的目的是使测试能够非常快速地运行和清理(丢弃RAM磁盘?)

我可以选择的两个最突出的选项是和。前者对我没有用处,因为我希望使用java.io.*API而不是Commons VFS类透明地工作。后者没有解决这个问题,因为我必须适应JDK 6(它应该是JDK 7的一部分),而且我不知道它是否能与java.io无缝地工作。*无论如何(我不会打赌)

也有解决方案,但我不能使用它们,原因与我不能使用Commons VFS相同。由于所讨论的库的复杂性,模拟是不可能的

在我的linux机器上,我可以轻松地创建一个RAM驱动器,并使用java.io.*API,就像处理磁盘上的文件一样。问题是,我希望它是跨平台的,更具体地说,使磁盘设置成为测试过程的一部分,而不是外部的

那么,有没有一种方法可以在Java中注册一个RAM驱动器,它可以与标准的Java.io.*API一起使用

那么,有没有一种方法可以在Java中注册一个RAM驱动器,它可以与标准的Java.io.*API一起使用

不适用于Java6或更早版本的JVM。Java6和更早版本不提供任何SPI来注册文件系统或文件系统类型。因此,要实现应用程序像普通FS一样使用的RAM FS,需要修改许多
java.io.*
类的行为


我认为您可以做的最好的事情是使用由主机操作系统实现的ramfs。您应该能够从Java访问它,就像它是一个普通的文件系统一样。但是,I/O需要系统调用,因此速度不会像RAM文件系统保存在JVM管理内存中那样快。

理论上斯蒂芬是对的。 但我可以给你建议一个窍门。您可以实现自己的FileInputStream和FileOutputStream,并将它们放入bootclasspath。例如,您的实现将实现open()、read()和readBytes()(这是常规FileInputStream中的本机方法)


这是针对您的问题的纯java解决方案。它的缺点是必须在单独的JVM实例中运行测试

您试图克服的基本问题是原始的
java.io
API根本不灵活(它们都指具体的类)。您可以将不同功能(例如
java.io.File
)放入的唯一方法是扩展基类

在设计类之后扩展类可能是糟糕的设计(只需查看
Properties
类),这就是为什么您可能找不到这样做的库的原因

没有什么可以阻止您自己扩展
java.io.File
类,并将所有方法代理到Commons VFS API的
FileObject

编辑:但是,在这种方法下,有些事情可能会失败-例如,使用接受父文件的
文件
构造函数

编辑2:好吧,我将从以下内容开始:

public class VirtualFile extends java.io.File {
    public static VirtualFile fromFile(File file) {
        if (file instanceof VirtualFile) {
            return (VirtualFile) file;
        } else {
            FileSystemManager fsm = new DefaultFileSystemManager();
            return fsm.toFileObject(file);
        }
    }

    private final org.apache.commons.vfs.FileObject mProxyFileObject;


    public VirtualFile(FileObject proxy) {
        super("/tmp/xxxx"); // That part needs some work to be cross-platform.
                            // However, such a construction will completely
                            // destroy the expectations that other classes 
                            // have about what a File is.
        mProxyFileObject = proxy;
    }

    public VirtualFile(VirtualFile parent, String child) {
        this(parent.mProxyFileObject.resolveFile(child));
    }

    public VirtualFile(File parent, String child) {
        this(fromFile(parent), child);
    }

    @Override
    public boolean canExecute() {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean canRead() {
        try {
            return mProxyFileObject.isReadable();
        } catch (FileSystemException fse) {
            // FileSystemException is not a Runtime Exception :(
            throw new RuntimeException(fse);
        }
    }

    // Override ALL public methods to throw Exceptions; 
    // implement or mock only the methods that you need.
}
至于为什么
文件(File,String)
构造函数不能与该设置一起工作:该构造函数不希望
文件
的实现破坏类的契约——我们调用
super(“/tmp/xxxx”)
时就是这样做的。(我们无法避免破坏类的契约,因为我们想要处理的虚拟文件没有普通的
文件
等价物)


因此,您就在这里—这需要一点不平凡的工作,而且该库很有可能无法按预期工作。

为什么不查看Java之外的内容。在操作系统级别创建一个RAM磁盘(针对WIndows和Linux的工具已经存在),并将您的库作为路径。我已经解释了原因:我理想地希望该过程与平台无关。此外,我更喜欢Java中的任何必要代码,而不是编写外部脚本来在一个或另一个环境中设置和处置RAM磁盘。您找到解决方案了吗?对于Java 7或Java 8。@Jus12抱歉,我还没有听说过解决方案。这不是真正的“纯Java”,因为修改系统类不在Java规范的范围内,也就是说,这可能适用于某些Java实现,但不适用于其他实现。我的理解是,即使他愿意,他也不能这样做。他说:“他后来没有剪掉它,因为我必须适应JDK6。”。如果他用自定义版本替换
java.io.*
类,那么它就不再是Java6了。(事实上,技术上它根本不是Java!)此外,替换标准Java类肯定不是“纯Java”;请参阅此链接-。根据被黑客攻击的JVM,你的代码会自动变得不可移植,因此不是“纯Java”,依我看。谢谢你的建议,Alex。使用RAM驱动器实现这些类并管理不同版本的JVM似乎是一项相当艰巨的工作,而且有一种黑客的感觉。从我读到的文章中,我的用例非常常见,因此我希望有更简单的东西,更重要的是,我不能为优化问题分配太多时间这很可能是完成工作的一种有效方法,不过:我会把它留给日程安排比较宽松的人去调查。@Stephen:修改一组选定的JDK 6类,以便能够运行单元测试(即不在生产中使用),这比使用JDK 7(不同于JDK 7)对我来说更容易接受