如何在Java中映射(mmap)linux块设备(例如/dev/sdb)?

如何在Java中映射(mmap)linux块设备(例如/dev/sdb)?,java,java-native-interface,mmap,memory-mapping,Java,Java Native Interface,Mmap,Memory Mapping,我可以使用Java.nio用Java读/写linux块设备。以下代码起作用: Path fp = FileSystems.getDefault().getPath("/dev", "sdb"); FileChannel fc = null; try { fc = FileChannel.open(fp, EnumSet.of(StandardOpenOption.READ, StandardOpenOption.WRITE)); } catch (Exception e) { Syste

我可以使用
Java.nio
用Java读/写linux块设备。以下代码起作用:

Path fp = FileSystems.getDefault().getPath("/dev", "sdb");
FileChannel fc = null;
try {
  fc = FileChannel.open(fp, EnumSet.of(StandardOpenOption.READ, StandardOpenOption.WRITE));
} catch (Exception e) {
  System.out.println("Error opening file: " + e.getMessage());
}
ByteBuffer buf = ByteBuffer.allocate(50);
try {
  if(fc != null)
    fc.write(buf);
} catch (Exception e) {
  System.out.println("Error writing to file: " + e.getMessage());
}
但是,内存映射不起作用。以下代码失败

MappedByteBuffer mbb = null;
try {
  mbb = fc.map(FileChannel.MapMode.READ_WRITE, 0, 100);
} catch (IOException e) {
  System.out.println("Error mapping file: " + e.getMessage());
}
此操作失败并出现错误:

java.io.IOException: Invalid argument
    at sun.nio.ch.FileDispatcherImpl.truncate0(Native Method)
    at sun.nio.ch.FileDispatcherImpl.truncate(FileDispatcherImpl.java:79)
    at sun.nio.ch.FileChannelImpl.map(FileChannelImpl.java:817)
有办法解决这个问题吗?也许通过使用不同的库?我在某个地方读到,也许通过使用JNI我可以做到这一点,但我找不到任何来源。

根据实际映射文件的机制留给实现。实现似乎正在尝试截断文件(可能是因为块设备大小与您指定的大小不同?)

我很好奇为什么您直接从块设备读取数据(除非您试图编写某种文件系统实用程序或需要执行原始I/O的东西)。如果需要以内存映射文件的形式直接从块设备读取,则可能需要编写一些C/C++代码来映射文件并处理对其的读取/写入,并使用Java/JNI桥接类来桥接对C/C++代码的调用。通过这种方式,您可以自己处理调用mmap(),并可以指定所需的任何选项。看看下面的例子,您可能无法在您的平台上指定块设备(我猜是Linux,但我可能错了)


如果您确实需要在Java中执行此操作,则可能需要执行适当长度和偏移量的read()调用和write()调用。

FileChannel.map尝试将文件截断为指定大小:

您需要获取块设备的大小,并将该确切大小传递给map调用


如果实际设备的大小大于可用内存,不要担心。操作系统将根据需要处理内存中的页面交换。

我发现最简单的方法是使用sun./
com.sun.*
magic。首先,您需要像这样包装
libc

import com.sun.jna.LastErrorException;
导入com.sun.jna.Library;
导入com.sun.jna.Native;
导入com.sun.jna.Pointer;
公共接口LibC扩展库{
LibC实例=(LibC)Native.loadLibrary(“c”,LibC.class);
指针mmap(指针地址,长长度,
int-protect、int-flags、int-fd、,
长偏移量)抛出LastErrorException;
//如果愿意,可以实现更多方法
}
然后你就快完了!您所需要的只是获取文件描述符。这可能有点棘手:

RandomAccessFile RandomAccessFile=新的RandomAccessFile(文件,“rw”);
int fd=sun.misc.SharedSecrets.getJavaIOFileDescriptorAccess()
.get(randomAccessFile.getFD());
就这样。现在您可以从java调用
libc

指针结果=LibC.instance.mmap(
/*将所需参数与获得的fd一起传递*/
);

这是你的真实代码吗?当然truncate()只在只写模式下调用?这就是为什么不能用stock类映射Linux帧缓冲区。但这是可以做到的。你必须实现一些东西才能达到目的。