【问题标题】:Can a java RAM disk be created to be used with the java.io.* API?可以创建一个 java RAM 磁盘以与 java.io.* API 一起使用吗?
【发布时间】:2011-05-24 14:45:15
【问题描述】:

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

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

我可以使用的两个最突出的选项是Commons VFSJSR 203。前者对我没有用,因为我希望使用 java.io.* API 而不是 Commons VFS 类透明地工作。后者没有削减它,因为我必须使用 JDK 6(它应该是 JDK 7 的一部分)而且我不知道它是否可以与 java.io.* 无缝工作(我不会赌注)。

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

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

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

【问题讨论】:

  • 为什么不看看 Java 之外的东西。在操作系统级别创建一个 RAM 磁盘(Windows 和 Linux 有工具),然后将您的库作为路径。
  • 我已经解释了原因:理想情况下,我希望该过程独立于平台。此外,我更喜欢使用 Java 编写任何必要的代码,而不是编写外部脚本来在一个或另一个环境中设置和处置 RAM 磁盘。
  • 您找到解决方案了吗?对于 Java 7 或 Java 8。
  • @Jus12 抱歉,目前我还没有听说过解决方案。

标签: java unit-testing ramdisk


【解决方案1】:

那么,有没有办法在 Java 中注册一个可用于标准 java.io.* API 的 RAM 驱动器?

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

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

【讨论】:

  • 感谢您提供清晰准确的答复。就目前而言,我可能会将测试降级为集成测试并使用它们。
【解决方案2】:

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

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

【讨论】:

  • 它不是真正的“纯 Java”,因为修改系统类不在 Java 规范的范围内,也就是说,这可能适用于某些 Java 实现,但不适用于其他实现。
  • 我的理解是他不能那样做,即使他想那样做。他说“[t]他后来没有剪掉它,因为我不得不使用 JDK 6”。如果他用自定义版本替换 java.io.* 类,那么它不再是 Java 6。 (实际上,从技术上讲,它根本不是 Java!)
  • 此外,替换标准 Java 类绝对不是“纯 Java”;看到这个链接-javacoffeebreak.com/faq/faq0006.html。依赖于被黑的 JVM 会自动使您的代码不可移植,因此不是“纯 Java”,IMO。
  • 谢谢你的建议,亚历克斯。实现这些类以使用 RAM 驱动器工作并管理不同版本的 JVM 似乎是一项相当多的工作,并且给人一种 hackish 的感觉。从我阅读的文章来看,我的用例非常频繁,所以我希望有更直接的东西,尤其是因为我不能为优化问题分配太多时间。 :\ 这很可能是完成工作的有效方法,但是:我会将其留给日程安排较宽松的人进行调查。
  • @Stephen:修改一组选定的 JDK 6 类以能够运行单元测试(即不用于生产)对我来说比使用例如更容易接受。 JDK 7 全面不同。对我来说,问题是它似乎需要几天而不是几个小时的工作,我现在负担不起。
【解决方案3】:

您要克服的基本问题是原始java.io API 根本不灵活(它们都引用具体类)。您可以在其中添加不同功能的唯一方法(例如 java.io.File)是扩展基类。

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

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

编辑:但是,在这种方法下,有些事情可能会失败 - 例如,使用采用父 FileFile 构造函数。

编辑 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(File, String) 构造函数不能与该设置一起工作:该构造函数不期望File 的实现会破坏类的契约——我们在调用super("/tmp/xxxx") 时会这样做。 (而且我们无法避免违反类的约定,因为我们要使用的虚拟文件没有普通的 File 等效项)

所以,你到了 - 这需要做一些不平凡的工作,而且库很可能无法按预期工作。

【讨论】:

  • 您能否详细说明如何将调用从 java.io.File 代理到例如一个 FileObject 以及 File(File) 构造函数的问题是什么?
  • 感谢您的详细说明,Jean。不幸的是,与简单地使用 Commons VFS 相比,我看不到它如何改善这种情况。我正在使用的第 3 方库不知道 VirtualFile 类,并且(当然)不会使用它。如果它被编写为使用像您描述的那样的抽象层,那可能会给我一些工作。看来我暂时会被磁盘上的文件卡住。
  • @Tomislav:我不知道你对图书馆有多大的控制权——或者也许你可以为图书馆提供一个基本的File
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-04
  • 2012-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-29
相关资源
最近更新 更多