Можно ли создать виртуальный диск Java для использования с API java.io.*?

Я использую стороннюю библиотеку, которая в основном создает выходной каталог с различными типами файлов и подкаталогов внутри. Я хотел бы иметь возможность писать модульные тесты, чтобы подтвердить правильность вывода.

Я хотел бы иметь возможность использовать библиотеку с RAM-диском, чтобы никакая библиотека не касалась реальных дисковых пластин. Идея состоит в том, чтобы сделать тесты очень быстрыми для запуска и очистки (удалить RAM-диск?).

Мне доступны два наиболее важных варианта: Commons VFS и JSR 203. Первое для меня бесполезно, потому что я хочу, чтобы все работало прозрачно, используя java.io.* API, а не классы Commons VFS. Последнее не подходит, потому что мне приходится обходиться JDK 6 (он должен быть частью JDK 7), и я в любом случае не знаю, будет ли он без проблем работать с java.io. * (я бы не стал сделать ставку на него).

Существуют и другие решения, но я не могу их использовать по той же причине, что и не может использовать Commons VFS. О моках не может быть и речи из-за сложности рассматриваемой библиотеки.

На моей Linux-машине я могу легко создать RAM-диск и использовать java.io.* API так же, как и с файлами на диске. Дело в том, что я хочу, чтобы он был кроссплатформенным, а точнее, чтобы настройка диска была частью процедуры тестирования, а не чем-то внешним.

Итак, есть ли способ зарегистрировать RAM-диск в Java, который можно было бы использовать со стандартным API java.io.*?


person Tomislav Nakic-Alfirevic    schedule 13.12.2010    source источник
comment
Почему бы не посмотреть за пределы Java. Создайте RAM-диск на уровне ОС (инструменты существуют для WIndows и Linux) и просто укажите путь к своей библиотеке.   -  person    schedule 13.12.2010
comment
Я уже объяснял почему: в идеале я хотел, чтобы процедура была платформенно-независимой. Кроме того, я бы предпочел, чтобы любой необходимый код был на Java, а не писал внешние сценарии для настройки и удаления RAM-диска в той или иной среде.   -  person Tomislav Nakic-Alfirevic    schedule 13.12.2010
comment
Вы нашли решение? Для Java 7 или Java 8.   -  person Jus12    schedule 02.12.2016
comment
@ Jus12 Извините, пока я не слышал о решении.   -  person Tomislav Nakic-Alfirevic    schedule 03.12.2016


Ответы (3)


Итак, есть ли способ зарегистрировать RAM-диск в Java, который можно было бы использовать со стандартным API java.io.*?

Не с Java 6 или более ранней JVM. Java 6 и более ранние версии не предоставляют SPI для регистрации файловых систем или типов файловых систем. Таким образом, реализация RAM FS, которую приложение будет использовать как обычную FS, повлечет за собой изменение поведения ряда java.io.* классов.

Я думаю, что лучшее, что вы могли бы сделать, это использовать RAM FS, реализованную операционной системой хоста. Вы должны иметь доступ к этому из Java, как если бы это была обычная файловая система. Однако ввод-вывод повлечет системные вызовы, поэтому он будет не таким быстрым, как если бы файловая система RAM находилась в управляемой памяти JVM.

person Stephen C    schedule 13.12.2010
comment
Спасибо за четкий и четкий ответ. В нынешнем виде я, вероятно, перейду от тестов к интеграционным и буду работать с ними. - person Tomislav Nakic-Alfirevic; 13.12.2010

Теоретически Стивен прав. Но я могу предложить вам хитрость. Вы можете реализовать свои собственные FileInputStream и FileOutputStream и поместить их в bootclasspath. Ваша реализация, например, будет реализовывать open(), read() и readBytes() (которые являются собственным методом в обычном FileInputStream.)

Это чистое Java-решение для вашей проблемы. Его недостаток в том, что вам нужно запускать свои тесты в отдельном экземпляре JVM.

person AlexR    schedule 13.12.2010
comment
Это не совсем чистая Java, поскольку изменение системных классов не входит в объем спецификаций Java, т.е. это может работать на некоторых реализациях Java, но не будет работать на других. - person Joachim Sauer; 13.12.2010
comment
Я так понимаю, что он не может этого сделать, даже если захочет. Он говорит, что [t]позже он не стал его сокращать, потому что мне приходится обходиться JDK 6. Если он заменит java.io.* классы пользовательскими версиями, то это уже не Java 6. (Ведь технически это вообще не Java!) - person Stephen C; 13.12.2010
comment
кроме того, замена стандартных классов Java определенно НЕ является чистой Java; см. эту ссылку - javacoffeebreak.com/faq/faq0006.html . В зависимости от взломанной JVM ваш код автоматически становится непереносимым и, следовательно, не чистой Java, IMO. - person Stephen C; 13.12.2010
comment
Спасибо за предложение, Алекс. Реализация этих классов для работы с использованием RAM-диска и управления различными версиями JVM кажется довольно трудоемкой и имеет хакерский вид. Судя по статьям, которые я читал, мой вариант использования довольно частый, поэтому я надеялся на что-то более простое, тем более, что я не могу уделять слишком много времени задаче оптимизации. :\ Тем не менее, это вполне может быть правильным подходом к выполнению работы: я оставлю это для исследования кому-то с более свободным графиком. - person Tomislav Nakic-Alfirevic; 13.12.2010
comment
@Stephen: изменение выбранного небольшого набора классов JDK 6, чтобы иметь возможность запускать модульные тесты (т. Е. Не использовать в производстве), было бы для меня более приемлемым, чем использование, например. JDK 7, который отличается по всем направлениям. Проблема для меня в том, что это требует дней, а не часов работы, которую я не могу себе позволить прямо сейчас. - person Tomislav Nakic-Alfirevic; 13.12.2010

Основная проблема, которую вы пытаетесь решить, заключается в том, что исходные java.io API совсем не гибкие (все они относятся к конкретным классам). Единственный способ добавить другую функциональность, например java.io.File, — это расширить базовый класс.

Расширение классов после того, как они разработаны, может быть плохим дизайном (просто посмотрите на класс Properties) - поэтому вы, вероятно, не найдете библиотеку, которая делает это.

Ничто не мешает вам расширить класс java.io.File самостоятельно, а все методы проксировать, например, на FileObject Commons VFS API.

Изменить. Тем не менее, есть вещи, которые, вероятно, не сработают при таком подходе, например, использование конструкторов File, принимающих родительский элемент 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 эквивалента)

Итак, вот и все — это потребует нетривиальной работы, и есть значительный шанс, что библиотека все равно не будет работать так, как ожидалось.

person Jean Hominal    schedule 13.12.2010
comment
Не могли бы вы немного рассказать о том, как вы будете проксировать вызовы из java.io.File, например. a FileObject и в чем проблема с конструктором File (File)? - person Tomislav Nakic-Alfirevic; 13.12.2010
comment
Спасибо за довольно подробное разъяснение, Жан. К сожалению, я не вижу, как это улучшает ситуацию по сравнению с простым использованием Commons VFS. Используемая мной сторонняя библиотека не знает о классе VirtualFile и (конечно) не будет его использовать. Если бы он был написан для использования уровня абстракции, такого как тот, который вы описали, это могло бы дать мне что-то, с чем можно было бы поработать. Кажется, я пока застряну с файлами на диске. - person Tomislav Nakic-Alfirevic; 13.12.2010
comment
@Tomislav: я не знал, насколько вы контролируете библиотеку - или, может быть, вы могли бы предоставить базовую File библиотеке. - person Jean Hominal; 13.12.2010