使用Java NIO直接访问Windows磁盘 [英] Accessing Windows disks directly with Java NIO

查看:2048
本文介绍了使用Java NIO直接访问Windows磁盘的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用一个使用Java NIO的库,以便直接将文件映射到内存,但是我无法直接读取磁盘。

I am using a library that uses Java NIO in order to directly map files to memory, but I am having trouble reading disks directly.

可以使用UNC直接使用 FileInputStream 读取磁盘,例如

I can read the disks directly using FileInputStream with UNC, such as

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:

However, I can't extend this to 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");
}

堆栈跟踪(最直接原因)是:

The stacktrace (up to the cause) is:

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或类似的东西下列出所有设备?

I haven't been able to find a solution, though I saw something close on How to access specific raw data on disk from java. The answer by Daniel Alder suggesting the use of GLOBALROOT seems to be relevant, as the answer uses FileChannel in the answer, but I can't seem to find the drive using this pattern. Is there a way to list all devices under GLOBALROOT or something like that?

目前我正在寻找用直接替换NIO的用途InputStream s,但如果可以,我想避免这种情况。首先,使用NIO是有原因的,其次,它运行了大量代码,需要大量工作。最后,我想知道如何实现Daniel的解决方案,以便我可以在未来写入设备或使用NIO。

At the moment I am looking at replacing uses of NIO with straight InputStreams, but I want to avoid this if I can. Firstly, NIO was used for a reason, and secondly, it runs through a lot of code and will require a lot of work. Finally, I'd like to know how to implement something like Daniel's solution so that I can write to devices or use NIO in the future.

总结:怎么能我直接使用Java NIO(不是 InputStream s)访问驱动器,和/或有没有办法列出可通过GLOBALROOT访问的所有设备,以便我可以使用Daniel Alser的解决方案?

So in summary: how can I access drives directly with Java NIO (not InputStreams), and/or is there a way to list all devices accessible through GLOBALROOT so that I might use Daniel Alser's solution?

答案摘要:
我保留了过去的编辑(如下)以避免混淆。在EJP和Apangin的帮助下,我我有一个可行的解决方案。类似

Summary of Answers: I have kept the past edits (below) to avoid confusion. With the help of EJP and Apangin I think I have a workable solution. Something like

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,并且出现将其转换为一个是安全的。

This will work as long as the posn parameter is a multiple of the sector size (set at 512 in this case). Note that this also works with the Channels.newChannel(FileInputStream), which seems to always return a SeekableByteStream in this case and it appears it is safe to cast it to one.

从快速和肮脏的测试出现这些方法真正寻求并且不仅仅是跳过。我在驱动器开始时搜索了一千个位置,然后读取它们。我做了同样的事情,但增加了一半磁盘大小的偏移量(搜索磁盘后面)。我找到了:

From quick and dirty testing it appears that these methods truly do seek and don't just skip. I searched for a thousand locations at the start of my drive and it read them. I did the same but added an offset of half of the disk size (to search the back of the disk). I found:


  • 这两种方法花了几乎相同的时间。

  • 搜索开头或结尾
  • 影响时间的磁盘。
  • 减少地址范围 减少时间。

  • 对地址进行排序确实减少了时间,但不是很多。

  • Both methods took almost the same time.
  • Searching the start or the end of the disk did not affect time.
  • Reducing the range of the addresses did reduce time.
  • Sorting the addresses did reduce time, but not by much.

这对我来说意味着这是真正的追求,而不仅仅是阅读和跳过(作为流倾向于)。在这个阶段速度仍然很糟糕,它使我的硬盘听起来像一台洗衣机,但代码是为快速测试而设计的,并且尚未完美。它可能仍然可以正常工作。

This suggests to me that this is truly seeking and not merely reading and skipping (as a stream tends to). The speed is still terrible at this stage and it makes my hard drive sound like a washing machine, but the code was designed for a quick test and has yet to be made pretty. It may still work fine.

感谢EJP和Apangin的帮助。在他们各自的答案中阅读更多内容。

Thanks to both EJP and Apangin for the help. Read more in their respective answers.

编辑:
我已经在Windows 7计算机上运行了我的代码(我没有'最初有一个),我得到一个略有不同的例外(见下文)。这是使用管理员权限运行的,第一段代码仍然可以在相同条件下运行。

I have since run my code on a Windows 7 machine (I didn't have one originally), and I get a slightly different exception (see below). This was run with admin privileges, and the first piece of code still works under the same conditions.

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,我尝试过:

Edit 2: In response to EJP, I have tried:

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

当我尝试这个时,我得到以下输出:

When I try this I get the following output:


创建频道

麻烦:java.io.IOException:参数不正确

Channel created
Oh bother: java.io.IOException: The parameter is incorrect

所以看来我可以创建一个FileChannel或ReadableByteChannel,但我不能使用它;也就是说,错误只是延迟。

So it appears that I can create a FileChannel or ReadableByteChannel, but I can't use it; that is, the error is simply deferred.

推荐答案

在没有缓冲的情况下访问物理驱动器时,您只能读取完整的扇区。这意味着,如果扇区大小为512字节,则只能读取512个字节的倍数。将缓冲区长度更改为512或4096(无论您的扇区大小是多少)和 FileChannel 将正常工作:

When accessing physical drive without buffering, you can read only complete sectors. This means, if a sector size is 512 bytes, you can read only multiple of 512 bytes. Change your buffer length to 512 or 4096 (whatever your sector size is) and FileChannel will work fine:

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

参见对齐和文件访问要求

你的原始 FileInputStream 代码显然是因为 BufferedInputStream ,其默认缓冲区大小为8192.把它带走 - 并且代码将以相同的异常失败。

Your original FileInputStream code works obviously because of BufferedInputStream which has the default buffer size of 8192. Take it away - and the code will fail with the same exception.

这篇关于使用Java NIO直接访问Windows磁盘的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆