Предварительное выделение дискового пространства для хранения файлов
Существует ли способ Java предварительно выделить дисковое пространство для исключительного использования в приложении?
Нет необходимости в том, чтобы это пространство было отдельной файловой системой или частью существующей файловой системы (таким образом, это может быть база данных), но оно должно позволять резервировать указанный объем пространства и допускать случайные операции чтения/записи с достаточно высокой пропускной способностью.
4 ответа:
Можно попробовать использовать объект RandomAccessFile и использовать метод setLength ().
Пример:
File file = ... //Create a temporary file on the filesystem your trying to reserve. long bytes = ... //number of bytes you want to reserve. RandomAccessFile rf = null; try{ rf = new RandomAccessFile(file, "rw"); //rw stands for open in read/write mode. rf.setLength(bytes); //This will cause java to "reserve" memory for your application by inflating/truncating the file to the specific size. //Do whatever you want with the space here... }catch(IOException ex){ //Handle this... }finally{ if(rf != null){ try{ rf.close(); //Lets be nice and tidy here. }catch(IOException ioex){ //Handle this if you want... } } }
Примечание: файл должен существовать до создания объекта RandomAccessFile.
Объект RandomAccessFile затем можно использовать для чтения / записи в файл. Убедитесь, что в целевой файловой системе достаточно свободного места. Пространство не может быть "эксклюзивным", но вы всегда можете использовать блокировки файлов для этого.
P. S: Если вы в конечном итоге осознаете, что жесткие диски медленные и бесполезные (или предназначенный для использования оперативной памяти с самого начала) вы можете использовать объект ByteBuffer из java.НИО. Методов allocate() и allocateDirect() должно быть более чем достаточно. Байтовый буфер будет выделен в оперативную память (и возможный SwapFile) и будет исключительным для этой java-программы. Произвольный доступ может быть осуществлен путем изменения положения буфера. Так как эти буферы используют целые числа со знаком для опорной позиции, максимальные размеры ограничены 2^31-1.
Подробнее о RandomAccessFile Здесь .
Подробнее о FileLock (объекте java) читайте здесь.
Подробнее о ByteBuffer читайте здесь.
Вот урезанная версия моего решения на основе JNA
fallocate
. Основная хитрость заключается в получении собственного файлового дескриптора. До сих пор я тестировал его только на Linux, но он должен работать на всех современных системах POSIX/non-Windows. В Windows это не нужно, так как Windows по умолчанию не создает разреженные файлы (только сStandardOpenOption.SPARSE
), поэтому там достаточноRandomAccessFile.setLength(size)
илиFileChannel.write(ByteBuffer.allocate(1), size - 1)
./** * Provides access to operating system-specific {@code fallocate} and * {@code posix_fallocate} functions. */ public final class Fallocate { private static final boolean IS_LINUX = Platform.isLinux(); private static final boolean IS_POSIX = !Platform.isWindows(); private static final int FALLOC_FL_KEEP_SIZE = 0x01; private final int fd; private int mode; private long offset; private final long length; private Fallocate(int fd, long length) { if (!isSupported()) { throwUnsupported("fallocate"); } this.fd = fd; this.length = length; } public static boolean isSupported() { return IS_POSIX; } public static Fallocate forChannel(FileChannel channel, long length) { return new Fallocate(getDescriptor(channel), length); } public static Fallocate forDescriptor(FileDescriptor descriptor, long length) { return new Fallocate(getDescriptor(descriptor), length); } public Fallocate fromOffset(long offset) { this.offset = offset; return this; } public Fallocate keepSize() { requireLinux("fallocate keep size"); mode |= FALLOC_FL_KEEP_SIZE; return this; } private void requireLinux(String feature) { if (!IS_LINUX) { throwUnsupported(feature); } } private void throwUnsupported(String feature) { throw new UnsupportedOperationException(feature + " is not supported on this operating system"); } public void execute() throws IOException { final int errno; if (IS_LINUX) { final int result = FallocateHolder.fallocate(fd, mode, offset, length); errno = result == 0 ? 0 : Native.getLastError(); } else { errno = PosixFallocateHolder.posix_fallocate(fd, offset, length); } if (errno != 0) { throw new IOException("fallocate returned " + errno); } } private static class FallocateHolder { static { Native.register(Platform.C_LIBRARY_NAME); } private static native int fallocate(int fd, int mode, long offset, long length); } private static class PosixFallocateHolder { static { Native.register(Platform.C_LIBRARY_NAME); } private static native int posix_fallocate(int fd, long offset, long length); } private static int getDescriptor(FileChannel channel) { try { // sun.nio.ch.FileChannelImpl declares private final java.io.FileDescriptor fd final Field field = channel.getClass().getDeclaredField("fd"); field.setAccessible(true); return getDescriptor((FileDescriptor) field.get(channel)); } catch (final Exception e) { throw new UnsupportedOperationException("unsupported FileChannel implementation", e); } } private static int getDescriptor(FileDescriptor descriptor) { try { // Oracle java.io.FileDescriptor declares private int fd final Field field = descriptor.getClass().getDeclaredField("fd"); field.setAccessible(true); return (int) field.get(descriptor); } catch (final Exception e) { throw new UnsupportedOperationException("unsupported FileDescriptor implementation", e); } } }
В системах Linux можно использовать системный вызов fallocate (). Это очень быстро. Просто запустите команду Bash.
UPD:
fallocate -l 10G 10Gigfile
Вы можете предварительно выделить место, написав большой файл, но, честно говоря, я бы не стал беспокоиться. Производительность будет довольно хорошей/ вероятно, лучше, чем вам нужно.
Если бы вам действительно нужна была производительность, вы бы писали C++/C# и делали RAW I / O.
Но это обычно делается только при написании движка СУБД, захвата больших объемов мультимедиа или аналогичного.