13

基本的に、さまざまな種類のファイルとサブディレクトリを含む出力ディレクトリを作成するサードパーティのライブラリを使用しています。出力が正しいことを確認するための単体テストを作成できるようにしたいと考えています。

ライブラリが実際のディスクプレートにまったく触れないように、RAMディスクでライブラリを使用できるようにしたいと思います。アイデアは、テストの実行とクリーンアップを非常に高速にすることです (RAM ディスクを削除しますか?)。

私が利用できる最も顕著な 2 つのオプションは、Commons VFSJSR 203です。Commons VFS クラスではなく、java.io.* API を使用して透過的に動作させたいので、前者は役に立ちません。私はJDK 6(JDK 7の一部であるはずです)で間に合わせる必要があり、とにかくJava.io.*とシームレスに動作するかどうかわからないため、後者はそれをカットしません(私はしませんそれに賭ける)。

他の解決策もありますが、Commons VFS を使用できないのと同じ理由で使用できません。問題のライブラリの複雑さのため、モックは問題外です。

私の Linux マシンでは、簡単に RAM ドライブを作成し、ディスク上のファイルと同じように java.io.* API を使用できます。問題は、クロスプラットフォームであり、より具体的には、ディスクのセットアップを外部のものではなく、テスト手順の一部にしたいということです。

では、標準の java.io.* API で使用できる Java で RAM ドライブを登録する方法はありますか?

4

3 に答える 3

6

では、標準の java.io.* API で使用できる Java で RAM ドライブを登録する方法はありますか?

Java 6 以前の JVM では使用できません。Java 6 以前は、ファイル システムまたはファイル システム タイプを登録するための SPI を提供しません。そのため、アプリケーションが通常の FS のように使用する RAM FS を実装するには、多くのjava.io.*クラスの動作を変更する必要があります。

ホスト オペレーティング システムによって実装された RAM FS を使用するのが最善の方法だと思います。通常のファイル システムであるかのように、Java からアクセスできるはずです。ただし、I/Oにはシステム コールが必要になるため、RAM ファイル システムが JVM 管理メモリに保持されている場合ほど高速ではありません。

于 2010-12-13T11:37:05.487 に答える
4

理論的にはスティーブンは正しい。しかし、私はあなたにトリックを提案することができます. 独自の FileInputStream と FileOutputStream を実装して、それらを bootclasspath に入れることができます。あなたの実装は、たとえば、open()、read()、および readBytes() (通常の FileInputStream のネイティブ メソッドです) を実装します。

これは、問題に対する純粋な Java ソリューションです。その欠点は、JVM の別のインスタンスでテストを実行する必要があることです。

于 2010-12-13T11:58:31.053 に答える
2

克服しようとしている基本的な問題は、元のjava.ioAPI がまったく柔軟性がないことです (それらはすべて具象クラスを参照します)。たとえば にさまざまな機能を追加できる唯一の方法はjava.io.File、基本クラスを拡張することです。

設計後にクラスを拡張することは、悪い設計になる可能性があります (Propertiesクラスを見てください)。これが、おそらくそれを行うライブラリを見つけられない理由です。

java.io.File自分でクラスを拡張し、すべてのメソッドをFileObjectCommons VFS APIなどにプロキシすることを妨げるものは何もありません。

編集:ただし、そのアプローチではおそらく失敗する可能性があります。たとえば、Fileparent を取るコンストラクターを使用する場合などFileです。

編集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等価物がないため、クラスの契約を破ることは避けられません)

これで、かなりの作業が必要になり、ライブラリが期待どおりに機能しない可能性が高くなります。

于 2010-12-13T12:21:54.290 に答える