简体   繁体   English

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

[英]How to memory map (mmap) a linux block device (e.g. /dev/sdb) in Java?

I can read/write a linux block device with Java using java.nio . 我可以使用java.nio读取/编写带有Java的linux块设备。 The following code works: 以下代码有效:

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());
}

However, memory mapping does not work. 但是,内存映射不起作用。 The following code fails : 以下代码失败

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

This fails with Error: 这失败,错误:

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)

Is there a work around to this? 有没有解决这个问题? Perhaps by using a different library? 也许通过使用不同的库? I read somewhere that maybe by using JNI I could do this, but I couldn't find any sources. 我在某个地方读到可能通过使用JNI我可以做到这一点,但我找不到任何来源。

According to the documentation the mechanics of actually mapping a file are left to the implementation. 根据文档 ,实际映射文件的机制留给实现。 It appears that the implementation is attempting to truncate the file (maybe because the block device size is not the same as the size you specify?). 似乎实现正在尝试截断文件(可能是因为块设备大小与您指定的大小不同?)。

I am curious why you are reading from the block device directly (unless you are trying to write some sort of filesystem utility or something that needs to do raw I/O). 我很好奇为什么你直接从块设备读取(除非你试图编写某种文件系统实用程序或需要做原始I / O的东西)。 If you need to read from the block device as a memory mapped file directly, you may need to write some C/C++ code to map the file and handle reading/writing to it and use a Java/JNI bridge class to bridge calls to your C/C++ code. 如果需要直接从块设备读取内存映射文件,则可能需要编写一些C / C ++代码来映射文件并处理读/写操作并使用Java / JNI桥接类来桥接对您的调用C / C ++代码。 That way you handle calling mmap() yourself and can specify any options you need. 这样你就可以自己处理调用mmap()并指定你需要的任何选项。 Looking at the mmap() documentation you may not be able to specify block devices on your platform (I'm guessing Linux but I could be wrong). 查看mmap()文档,您可能无法在平台上指定块设备(我猜Linux但我可能错了)。

If you absolutely need to do this within Java you may need to do read() calls and write() calls of the appropriate length and offset. 如果您绝对需要在Java中执行此操作,则可能需要执行具有适当长度和偏移量的read()调用和write()调用。

I found that the easiest approach is to use JNA and a bit of sun.* / com.sun.* magic. 我发现最简单的方法是使用JNA和一点sun.* / com.sun.* magic。 First of all you need to wrap libc like this: 首先,你需要像这样包装libc

import com.sun.jna.LastErrorException;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;

public interface LibC extends Library {
    LibC instance = (LibC) Native.loadLibrary("c", LibC.class);

    Pointer mmap(Pointer address, long length, 
                 int protect, int flags, int fd, 
                 long offset) throws LastErrorException;
    // implement more methods if you like
}

And then you are almost done! 然后你差不多完成了! All you need is to obtain file descriptor. 您所需要的只是获取文件描述符。 It may be a bit tricky: 这可能有点棘手:

RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
int fd = sun.misc.SharedSecrets.getJavaIOFileDescriptorAccess()
                               .get(randomAccessFile.getFD());

That's it. 而已。 Now you can call libc from java: 现在你可以从java调用libc了:

Pointer result = LibC.instance.mmap(
    /*pass your desired parameters along with obtained fd*/
);

FileChannel.map attempts to truncate the file to the specified size: See the implementation FileChannel.map尝试将文件截断为指定大小: 请参阅实现

You will need to get the size of the block device and pass that exact size to the map call. 您将需要获取块设备的大小并将该确切大小传递给地图调用。

Don't worry if the size of the actual device is larger than your available memory. 如果实际设备的大小大于可用内存,请不要担心。 The OS will handle swapping pages in and out of memory as needed. 操作系统将根据需要处理内存和内存交换页面。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何告诉Java将逻辑字体(例如SansSerif)映射到系统上的特定字体? - How do I tell Java to map a logical font (e.g. SansSerif) to a specific font on my system? Java Path 如何转换为例如 InputStream - How is Java Path converted to e.g. InputStream 如何在java中重新绘制特定区域(例如圆圈)? - How to repaint a specific area (e.g. circle) in java? 在 Java 中,每个共享引用是否占用另一个内存字(例如 32 位或 64 位)? - Does each shared reference take up another word of memory (e.g. 32 or 64 bits) in Java? Java优化的读/写共享资源/内存位置,无需Atomic API,例如AtomicInteger - Java optimized read/write a shared resource/memory location without Atomic API e.g. AtomicInteger 从现有变量创建一个 map(例如一个 Java 相当于 JavaScript 的`{varA, varB, varC}`) - Create a map from existing variables (e.g. a Java equivalent to JavaScript's `{varA, varB, varC}`) 使用该类是否更有效,例如Hashtable而不是接口,例如Map? - Is it more efficient to use the class, e.g. Hashtable than the interface, e.g. Map? Linux中的本机内存使用似乎比通过JVM本身(例如,通过JConsole)观察到的要高得多 - Native memory usage in Linux seems to be much higher than observed through JVM itself (e.g. through JConsole) Java编译器如何处理类型之外的缺失类型参数 <E> ,例如 <E extends Foo> - How does the java compiler treat missing type arguments for types besides <E>, e.g., <E extends Foo> 模块化OpenJDK11 Java映像在Linux上找不到动态库(例如libjava.so) - Modular OpenJDK11 Java image can't find dynamic libraries (e.g. libjava.so) on Linux
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM