我正在使用一个库,它使用Java NIO直接将文件映射到内存中,但我在尝试直接读取磁盘时遇到了问题。
我可以使用UNC(网络文件路径)和
堆栈跟踪(直到原因)为:
我虽然在如何从Java访问磁盘上特定的原始数据看到了类似的内容,但还是没能找到解决方案。 Daniel Alder的答案建议使用GLOBALROOT,因为该答案在答案中使用了FileChannel,但我似乎无法使用此模式找到驱动器。是否有一种方法可以列出GLOBALROOT下的所有设备或类似于此的东西?
目前,我正在查看使用普通
因此,总结一下:如何使用Java NIO直接访问驱动器(而不是
只要posn参数是扇区大小(在这种情况下设置为512)的倍数,这将起作用。请注意,这也适用于Channels.newChannel(FileInputStream),在这种情况下似乎总是返回一个SeekableByteStream,并且将其转换为一个似乎是安全的操作。
从快速而粗略的测试中,这些方法似乎确实进行了查找,而不仅仅是跳过。我在驱动器开头搜索了一千个位置并读取了它们。我做了同样的事情,但增加了磁盘大小的一半的偏移量(以搜索磁盘的后半部分)。我发现:
- 两种方法几乎花费相同的时间。 - 搜索磁盘的开头或结尾并不影响时间。 - 减少地址范围会减少时间。 - 对地址进行排序会减少时间,但不会减少多少。
这向我表明,这确实是寻址而不仅仅是读取和跳过(因为流倾向于那样做)。在这个阶段速度仍然很慢,它使我的硬盘听起来像一台洗衣机,但代码被设计为快速测试,尚未美化。它可能仍然正常工作。
感谢EJP和Apangin的帮助。请在他们各自的答案中阅读更多内容。
编辑: 我后来在Windows 7机器上运行了我的代码(起初我没有),并获得了稍微不同的异常(请参见下文)。这是在管理员权限下运行的,第一段代码在相同的条件下仍然有效。
当我尝试这样做时,我得到了以下输出:
我可以使用UNC(网络文件路径)和
FileInputStream
直接读取磁盘,例如:File disk = new File("\\\\.\\PhysicalDrive0\\");
try (FileInputStream fis = new FileInputStream(disk);
BufferedInputStream bis = new BufferedInputStream(fis)) {
byte[] somebytes = new byte[10];
bis.read(somebytes);
} catch (Exception ex) {
System.out.println("Oh bother");
}
然而,我无法将这个方法扩展到 NIO:
File disk = new File("\\\\.\\PhysicalDrive0\\");
Path path = disk.toPath();
try (FileChannel fc = FileChannel.open(path, StandardOpenOption.READ)){
System.out.println("No exceptions! Yay!");
} catch (Exception ex) {
System.out.println("Oh bother");
}
堆栈跟踪(直到原因)为:
java.nio.file.FileSystemException: \\.\PhysicalDrive0\: The parameter is incorrect.
at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:86)
at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:97)
at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:102)
at sun.nio.fs.WindowsFileSystemProvider.newFileChannel(WindowsFileSystemProvider.java:115)
at java.nio.channels.FileChannel.open(FileChannel.java:287)
at java.nio.channels.FileChannel.open(FileChannel.java:334)
at hdreader.HDReader.testcode(HDReader.java:147)
我虽然在如何从Java访问磁盘上特定的原始数据看到了类似的内容,但还是没能找到解决方案。 Daniel Alder的答案建议使用GLOBALROOT,因为该答案在答案中使用了FileChannel,但我似乎无法使用此模式找到驱动器。是否有一种方法可以列出GLOBALROOT下的所有设备或类似于此的东西?
目前,我正在查看使用普通
InputStream
替换NIO的用法,但如果可能的话,我想避免这样做。首先,NIO有其使用原因,其次,它运行了大量代码并需要大量工作。最后,我想知道如何实现类似于Daniel解决方案的操作,以便将来可以写入设备或使用NIO。因此,总结一下:如何使用Java NIO直接访问驱动器(而不是
InputStream
),或者是否有一种方法可以列出通过GLOBALROOT可访问的所有设备,以便我可以使用Daniel Alser的解决方案?
回答总结:
我保留了过去的编辑(下面)以避免混淆。在EJP和Apangin的帮助下,我认为我有一个可行的解决方案。类似于以下内容:private void rafMethod(long posn) {
ByteBuffer buffer = ByteBuffer.allocate(512);
buffer.rewind();
try (RandomAccessFile raf = new RandomAccessFile(disk.getPath(), "r");
SeekableByteChannel sbc = raf.getChannel()) {
sbc.read(buffer);
} catch (Exception ex) {
System.out.println("Oh bother: " + ex);
ex.printStackTrace();
}
return buffer;
}
只要posn参数是扇区大小(在这种情况下设置为512)的倍数,这将起作用。请注意,这也适用于Channels.newChannel(FileInputStream),在这种情况下似乎总是返回一个SeekableByteStream,并且将其转换为一个似乎是安全的操作。
从快速而粗略的测试中,这些方法似乎确实进行了查找,而不仅仅是跳过。我在驱动器开头搜索了一千个位置并读取了它们。我做了同样的事情,但增加了磁盘大小的一半的偏移量(以搜索磁盘的后半部分)。我发现:
- 两种方法几乎花费相同的时间。 - 搜索磁盘的开头或结尾并不影响时间。 - 减少地址范围会减少时间。 - 对地址进行排序会减少时间,但不会减少多少。
这向我表明,这确实是寻址而不仅仅是读取和跳过(因为流倾向于那样做)。在这个阶段速度仍然很慢,它使我的硬盘听起来像一台洗衣机,但代码被设计为快速测试,尚未美化。它可能仍然正常工作。
感谢EJP和Apangin的帮助。请在他们各自的答案中阅读更多内容。
编辑: 我后来在Windows 7机器上运行了我的代码(起初我没有),并获得了稍微不同的异常(请参见下文)。这是在管理员权限下运行的,第一段代码在相同的条件下仍然有效。
java.nio.file.FileSystemException: \\.\PhysicalDrive0\: A device attached to the system is not functioning.
at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:86)
at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:97)
at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:102)
at sun.nio.fs.WindowsFileSystemProvider.newFileChannel(WindowsFileSystemProvider.java:115)
at java.nio.channels.FileChannel.open(FileChannel.java:287)
at java.nio.channels.FileChannel.open(FileChannel.java:335)
at testapp.TestApp.doStuff(TestApp.java:30)
at testapp.TestApp.main(TestApp.java:24)
编辑2: 针对EJP的回复,我已经尝试过:
byte[] bytes = new byte[20];
ByteBuffer bb = ByteBuffer.wrap(bytes);
bb.rewind();
File disk = new File("\\\\.\\PhysicalDrive0\\");
try (FileInputStream fis = new FileInputStream(disk);
ReadableByteChannel rbc = Channels.newChannel(new FileInputStream(disk))) {
System.out.println("Channel created");
int read = rbc.read(bb);
System.out.println("Read " + read + " bytes");
System.out.println("No exceptions! Yay!");
} catch (Exception ex) {
System.out.println("Oh bother: " + ex);
}
当我尝试这样做时,我得到了以下输出:
因此,似乎我可以创建FileChannel或ReadableByteChannel,但无法使用它们;也就是说,错误只是被推迟了。通道已创建
哎呀:java.io.IOException: 参数不正确
FileInput/OutputStreams
并在它们周围使用BufferedInput/OutputStreams
。 - user207421