是否可以创建 Java RAM 磁盘以与 java.io.* API 一起使用?

发布于 2024-10-07 08:02:18 字数 793 浏览 0 评论 0原文

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

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

我可用的两个最重要的选项是 Commons VFSJSR 203。前者对我来说没有用,因为我希望使用 java.io.* API 而不是 Commons VFS 类透明地工作。后者并不能解决问题,因为我必须使用 JDK 6(它应该是 JDK 7 的一部分),而且我不知道它是否能与 java.io.* 无缝工作(我不会)赌上它)。

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

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

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

I'm using a 3rd party library which basically creates an output directory with different kinds of files and subdirectories inside. I would like to be able to write unit tests to confirm that the output is correct.

I would like to be able to use the lib with a RAM disk, so that nothing the library does touches actual disk plates in any way. The idea is to make the tests very fast to run and clean up (drop RAM disk?).

The two most prominent options available to me are Commons VFS and JSR 203. The former is of no use to me because I want things to work transparently using the java.io.* API and not Commons VFS classes. The later doesn't cut it because I have to make do with JDK 6 (it's supposed to be a part of JDK 7) and I don't know if it will work seamlessly with java.io.* anyway (I wouldn't bet on it).

There are other solutions as well, but I can't use them for the same reason I can't use Commons VFS. Mocks are out of the question because of the complexity of the library in question.

On my linux machine, I can easily create a RAM drive and use the java.io.* API the same way I would with files on disk. The thing is, I want it to be cross-platform and more specifically, to make disk setup a part of the test procedure, rather than something external.

So, is there a way to register a RAM drive in Java which would be usable with the standard java.io.* API?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

江南月 2024-10-14 08:02:19

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

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

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

So, is there a way to register a RAM drive in Java which would be usable with the standard java.io.* API?

Not with a Java 6 or earlier JVM. Java 6 and earlier do not provide any SPI for registering file systems or file system types. So, to implement a RAM FS that an application would use like a normal FS would entail modifying the behavior of a number of java.io.* classes.

I think that the best thing that you could do would be to use a RAM FS implemented by the host operating system. You should be able to access that from Java as if it was a normal file system. However, I/O would entail a system calls, so it wouldn't be as fast as if the RAM file system was held in the JVM managed memory.

雪化雨蝶 2024-10-14 08:02:19

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

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

Theoretically Stephen is right.
But I can suggest you a trick. You can implement your own FileInputStream and FileOutputStream and put them into bootclasspath. Your implementation will for example implement open(), read() and readBytes() (that are native method in regular FileInputStream.)

This is pure java solution for your problem. Its disadvantage is that you have to run your tests in separate instance of JVM.

坐在坟头思考人生 2024-10-14 08:02:19

您要解决的基本问题是原始的 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 等效项)

所以,你就是这样 - 这将需要一些不平凡的东西工作,并且该库很有可能无法按预期工作。

The basic problem that you are seeking to overcome is that the original java.io APIs are not flexible at all (they all refer to concrete classes). The only way that you can put different functionality in, for example java.io.File, is by extending the base class.

Extending classes after they are designed can be bad design (Just look at the Properties class) - which is why you probably won't find a library that does that.

Nothing prevents you from extending the java.io.File class yourself, and proxy all the methods to, for example, a FileObject of the Commons VFS API.

Edit: However, there are things that will probably fail under that approach - for example, using the File constructors that take a parent File.

Edit 2: Well, I would begin with something like that:

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.
}

As for why the File(File, String) constructor would not work with that setup: that constructor does not expect an implementation of File to break the class's contract - which we do when we call super("/tmp/xxxx"). (And we can't avoid breaking the class's contract, because the virtual files that we want to work with do not have a plain File equivalent)

So, there you are - it would require a nontrivial bit of work, and there is a significant chance that the library would not work as expected anyway.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文