我正在使用一个使用Java NIO的库,以便直接将文件映射到内存,但是我无法直接读取磁盘。
我可以直接使用FileInputStream
使用UNC读取磁盘,例如
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");
}
stacktrace(由原因决定)是:
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)
虽然我在How to access specific raw data on disk from java看到了一些东西,但我找不到解决办法。 Daniel Alder的回答建议使用GLOBALROOT似乎是相关的,因为答案在答案中使用了FileChannel,但我似乎无法使用这种模式找到驱动器。有没有办法列出GLOBALROOT下的所有设备或类似的东西?
目前我正在考虑用直接InputStream
替换NIO的使用,但如果可以,我想避免这种情况。首先,使用NIO是有原因的,其次,它运行了大量代码,需要大量工作。最后,我想知道如何实现Daniel的解决方案,以便我可以在未来写入设备或使用NIO。
总结一下:如何直接使用Java NIO(而非InputStream
s)访问驱动器,和/或是否有办法列出可通过GLOBALROOT访问的所有设备,以便我可以使用Daniel Alser的解决方案?< / p>
答案摘要: 我保留了过去的编辑(下面)以避免混淆。在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);
}
当我尝试这个时,我得到以下输出:
频道创建了
哦,麻烦:java.io.IOException:参数不正确
所以看来我可以创建一个FileChannel或ReadableByteChannel,但我无法使用它;也就是说,错误只是推迟了。
答案 0 :(得分:3)
在没有缓冲的情况下访问物理驱动器时,您只能读取完整的扇区。这意味着,如果扇区大小为512字节,则只能读取512个字节的倍数。将缓冲区长度更改为512或4096(无论扇区大小如何),FileChannel
将正常工作:
ByteBuffer buf = ByteBuffer.allocate(512);
try (RandomAccessFile raf = new RandomAccessFile("\\\\.\\PhysicalDrive0", "r");
FileChannel fc = raf.getChannel()) {
fc.read(buf);
System.out.println("It worked! Read bytes: " + buf.position());
} catch (Exception e) {
e.printStackTrace();
}
请参阅Alignment and File Access Requirements。
您的原始FileInputStream
代码显然可以正常工作,因为BufferedInputStream
的默认缓冲区大小为8192.将其删除 - 代码将失败并出现相同的异常。
答案 1 :(得分:1)
以管理员身份运行此操作。它确实有效,因为它只是java.io:
try (FileInputStream fis = new FileInputStream(disk);
ReadableByteChannel fc = Channels.newChannel(fis))
{
System.out.println("No exceptions! Yay!");
ByteBuffer bb = ByteBuffer.allocate(4096);
int count = fc.read(bb);
System.out.println("read count="+count);
}
catch (Exception ex)
{
System.out.println("Oh bother: "+ex);
ex.printStackTrace();
}
编辑如果您需要随机访问,则会遇到RandomAccessFile
。通过Channels
没有映射。但是上面的解决方案不是NIO,而是FileInput/OutputStream
上的Java NIO层。
答案 2 :(得分:1)
使用NIO,您的原始代码只需要稍微改变一下。
Path disk = Paths.get("d:\\.");
try (ByteChannel bc = Files.newByteChannel(disk, StandardOpenOption.READ)) {
ByteBuffer buffer = ByteBuffer.allocate(10);
bc.read(buffer);
} catch (Exception e){
e.printStackTrace();
}
是好的,可行的代码,但我的版本和我的版本都出现了拒绝访问错误。