I use a library that uses Java NIO to directly map files to memory, but I cannot read disks directly.
I can read disks directly using FileInputStream with UNC, for example
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"); }
However, I cannot 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"); }
Column (before reason):
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)
I was not able to find a solution, although I saw something close on How to access certain raw data on disk from java . Daniel Alder's answer suggesting using GLOBALROOT seems to matter as the answer uses FileChannel in the answer, but I cannot find the drive using this template. Is there a way to list all devices under GLOBALROOT or something like that?
I am currently looking at replacing the use of NIO with direct InputStream s, but I want to avoid this if I can. Firstly, NIO was used for some reason, and secondly, it goes through a lot of code and will require a lot of work. Finally, I would like to know how to implement something like Daniel's solution so that I can write to devices or use NIO in the future.
So, in short: how can I access disks directly using Java NIO (not InputStream s) and / or is there a way to list all the devices available through GLOBALROOT so that I can use Daniel Alser?
Summary of responses: I retained past changes (below) to avoid confusion. Using 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; }
This will work as long as the posn parameter is a multiple of the sector size (in this case, 512). Note that this also works with Channel.newChannel (FileInputStream), which seems to always return a SeekableByteStream in this case, and it seems that it can be hidden by one.
From the quick and dirty testing, it seems that these methods are really looking and not just missing. I searched a thousand places at the beginning of my disc and read them. I did the same, but added an offset of half the size of the disk (for searching on the back of the disk). I found:
- Both methods took almost the same time.
- Finding the beginning or end of the disk did not affect the time.
- Reducing the address range has reduced the time.
- Sorting addresses has reduced time, but not by much.
This tells me what it is really looking for, not just reading and skipping (as the thread seeks). At this point, the speed is still terrible and my hard drive sounds like a washing machine, but the code was designed for quick testing and has yet to be made pretty pretty. It can still work fine.
Thanks to EJP and Apangin for helping. Read more in your answers.
Edit: Since then, I run my code on a computer running Windows 7 (I didnβt have it), and I get a slightly different exception (see below). This was done as an administrator, and the first part of the 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)
Edit 2: In response to EJP, I 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 to do this, I get the following output:
Channel created
Oh, worry: java.io.IOException: invalid parameter
So, it looks like I can create a FileChannel or ReadableByteChannel, but I cannot use it; that is, the error is simply delayed.