如何从Java访问特定的磁盘原始数据

19

我正在尝试使用以下代码来访问原始磁盘中偏移50个字节的一个字节。

randomAccessFile = new RandomAccessFile("C:", "r");
randomAccessFile.seek(50);
byte[] buffer = new byte[1];
randomAccessFile.read(buffer);

但我得到的只是以下错误:

java.io.FileNotFoundException: C: (Acceso denegado)
at java.io.RandomAccessFile.open(Native Method)
at java.io.RandomAccessFile.<init>(RandomAccessFile.java:212)
at java.io.RandomAccessFile.<init>(RandomAccessFile.java:98)
at pru.lseek.main(lseek.java:26)

有没有办法从Java中访问磁盘上的精确字节?

8个回答

19

我自己正在寻找从物理驱动器访问原始数据的可能性。现在我已经让它工作了,我只想告诉你如何做到。您可以直接从Java中访问原始磁盘数据...只需以管理员权限运行以下代码:

    File diskRoot = new File ("\\\\.\\PhysicalDrive0");
    RandomAccessFile diskAccess = new RandomAccessFile (diskRoot, "r");
    byte[] content = new byte[1024];
    diskAccess.readFully (content);

这将会获取系统中第一块物理硬盘的前kb数据。要访问逻辑驱动器,只需将“PhysicalDrive0”替换为驱动器号,例如“D:”

哦,是的......我在Win 7系统上尝试了Java 1.7 ...

只需查看物理驱动器的命名方式即可,网址为http://support.microsoft.com/kb/100027/en-us


谢谢这个。它有效。我使用了BufferedInputStream做了同样的事情。只需以管理员权限打开您的程序或CLI即可。我也使用了File对象,但是exists()方法不会返回正结果,所以请注意。 - Michael K
如何授予管理员权限。请回复。 - Pawan Yadav

15
如果您有兴趣在Windows下向原始卷写入内容,请尝试以下方法(需要Java 7)。
  String pathname;
  // Full drive:
  // pathname = "\\\\.\\PhysicalDrive0";
  // A partition (also works if windows doesn't recognize it):
  pathname = "\\\\.\\GLOBALROOT\\ArcName\\multi(0)disk(0)rdisk(0)partition(5)";

  Path diskRoot = ( new File( pathname ) ).toPath();

  FileChannel fc = FileChannel.open( diskRoot, StandardOpenOption.READ,
        StandardOpenOption.WRITE );

  ByteBuffer bb = ByteBuffer.allocate( 4096 );

  fc.position( 4096 );
  fc.read( bb );
  fc.position( 4096 );
  //fc.write( bb ); // careful!

  fc.close();

当然,您需要确保设备可写并且未被系统访问/锁定。还要确保您的应用程序以必要的特权运行(提升的特权)。
顺便说一下:使用“new RandomAccessFile(drive, "rw")”似乎不起作用,因为Java不会以与原始设备兼容的模式打开文件句柄(异常为“java.io.FileNotFoundException(参数不正确)”)。但是,使用RandomAccessFile也可以正常读取。

非常好的答案,感谢您特别使用NIO API来解决WRITE的问题。 - Riyad Kalla

4

RandomAccessFile不适用于打开目录以操纵条目,您需要创建或删除文件。 "Acceso denegado"可能意味着访问被拒绝。 无论如何,要做到这一点,您需要使用JNI。

编辑:您正在尝试的操作非常复杂,没有通用的方法可以实现。您可以按扇区访问硬盘,但是然后您必须解释其结构,这显然取决于文件系统,例如FAT、NTFS、HPFS等。


尝试通过JNI,但没有成功: fp = fopen("c:", "r")) <- 不会出错 fseek(fp, i, SEEK_SET) <- 不会出错 getc(fp) <- 无论fseek的i参数是什么,始终返回相同的数据 - user178973
请看这里如何读取磁盘扇区:http://www.codeguru.com/cpp/w-p/system/misc/article.php/c5765/ - stacker
非常感谢!解决了我的问题: fp = fopen("\\.\C:", "r")) 现在我只需要创建一个JNI库,但很奇怪竟然没有人创建它。 - user178973

3
在Linux下,您可以尝试打开/dev/<device>,例如/dev/hda/dev/sdb2。这将使您访问原始磁盘(或仅分区),但需要具有适当的权限,普通用户没有这些权限。

这就是我试图模拟的内容。 f=open("/dev/sda",O_RDONLY); - user178973

1

Java只能访问文件。Unix有“原始设备”的概念,将其作为/dev目录中的文件,因此你想要的在那里是可能的。但在Windows上不行,因为它没有这样的文件表示原始硬盘数据。


1
正如你现在可能已经知道的那样,Windows也有自己的访问原始设备的方法,使用一种称为“UNC文件”或“UNC路径”的东西。它们相当于用于访问远程资源的网络路径,例如\\resource,但是您必须使用\\.\resource引用自己的机器,其中resource例如为PhysicalDrive0 - Azurlake

1
在Windows中,您需要将原始设备标识符作为文件访问。如果您传递文件“\\.\c:”,则应该可以工作,您正在使用设备UNC名称\.\c:(\.表示此计算机)。
对于Vista及更高版本,我认为它不会正常工作,因为已经有机制防止除设备驱动程序之外的任何东西对磁盘进行原始访问(请勿引用我)。

1
:请注意,访问原始设备需要一些特权(取决于驱动器:可移动或不可移动/取决于WinXP的文件系统:允许iso9660,不允许FAT)。

还要注意读取的大小很重要(取决于操作系统): 在iso9660文件系统上,read(1024字节)适用于XP,但在Seven上失败。 在Seven上,它看起来必须块对齐:read(2048字节)有效。


0

假设我要创建一个JNI库,我不知道在'open' C函数中传递的第一个参数是什么: f=open("C:",O_RDONLY); ??? - user178973

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接