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

Tar*_*ill 7 java java-native-interface mmap memory-mapping

我可以用Java读/写一个linux块设备java.nio.以下代码有效:

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());
}
Run Code Online (Sandbox Code Playgroud)

但是,内存映射不起作用.以下代码失败:

MappedByteBuffer mbb = null;
try {
  mbb = fc.map(FileChannel.MapMode.READ_WRITE, 0, 100);
} catch (IOException e) {
  System.out.println("Error mapping file: " + e.getMessage());
}
Run Code Online (Sandbox Code Playgroud)

这失败,错误:

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)
Run Code Online (Sandbox Code Playgroud)

有没有解决这个问题?也许通过使用不同的库?我在某个地方读到可能通过使用JNI我可以做到这一点,但我找不到任何来源.

小智 3

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

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

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