是否有Java方法为应用程序中的独占使用预分配驱动器空间?
不要求此空间是单独的文件系统或现有文件系统的一部分(因此很容易成为数据库),但它应该允许保留指定的空间量并允许随机读取/写入高足够的吞吐量。
答案 0 :(得分:9)
这是我基于JNA的fallocate
解决方案的精简版本。主要技巧是获取本机文件描述符。到目前为止,我只在Linux上进行了测试,但它应该适用于所有现代POSIX /非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);
}
}
}
答案 1 :(得分:8)
您可以尝试使用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:如果您最终意识到硬盘驱动器速度慢且无用(或者从一开始就意味着使用RAM),您可以使用java.nio中的ByteBuffer对象。 allocate()和allocateDirect()方法应该足够了。字节缓冲区将被分配到RAM(和可能的SwapFile)中,并且将独占于此java程序。可以通过改变缓冲区的位置来进行随机访问。由于这些缓冲区使用有符号整数来引用位置,因此最大大小限制为2 ^ 31 - 1。阅读有关RandomAccessFile here的更多信息。
详细了解FileLock(java对象)here。
详细了解ByteBuffer here。
答案 2 :(得分:0)
在Linux系统上,您可以使用fallocate()系统调用。它非常快。只需运行Bash命令。
<强> UPD:强>
fallocate -l 10G 10Gigfile
答案 3 :(得分:-4)
你可以通过写一个大文件来预先分配空间,但说实话我不会打扰。性能将非常好/可能比你需要的更好。
如果您确实需要性能,那么您将编写C ++ / C#并执行RAW I / O.
但这通常只在编写RDBMS引擎,大容量媒体捕获或类似内容时才会完成。