WMI:Win32_DiskDrive以获取物理磁盘驱动器上的总扇区

时间:2012-03-28 05:48:13

标签: python winapi wmi disk pywin32

我尝试使用Win32_DiskDrive获取磁盘的最大总扇区,但所有这些都返回了错误的值。我使用了HxD,这个程序返回了准确的值。我试图使用fdisk在Linux中获得整个扇区,它也准确地返回。

我注意到Win32_DiskDrive MSDN 中的注释如下:

  

此属性的值是通过BIOS中断13h的扩展功能获得的。如果驱动器使用转换方案来支持高容量磁盘大小,则该值可能不准确。有关精确的驱动器规格,请咨询制造商。

但我无法理解这意味着什么?以及如何解决这个问题?

更新1:

这是我的python脚本的剪辑代码。

必填:PythonPyWin32WMI

import wmi

c = wmi.WMI()
for diskDrive in c.query("SELECT * FROM Win32_DiskDrive"):
    print diskDrive.Name, "\nTotal Sector: ", diskDrive.TotalSectors

更新2:

根据要求,这里是检测到HxD总扇区的WMI片段。

  • WMI: 625137345(上)
  • HxD: 625142448(底部)

Sector Difference Screenshot

更新3:

如果有兴趣的话,您也可以在自己的计算机上试一试,看看Win32_DiskDrive是否报告了准确的结果。我在许多其他计算机(WinXP& 7)上尝试使用其他存储设备(硬盘,闪存盘等),但所有结果都不准确。

要尝试,请安装PythonPyWin32WMI

非常感谢

3 个答案:

答案 0 :(得分:2)

WMI报告的驱动器比实际小几MB。我认为这与Windows如何根据柱面/磁头/扇区处理驱动器有关。

我的解决方案是读取报告的驱动器大小的结尾,直到出现错误:

import wmi
disks = wmi.WMI().Win32_DiskDrive(MediaType="Removable Media")
for disk in disks:
    disk_size = int(disk.size)
    sector_size = disk.BytesPerSector
    print(disk.name, "reported size:", disk_size)
    with open(disk.name, "rb") as f:
        f.seek(disk_size)
        while True:
            try:
                f.read(sector_size)
                disk_size += sector_size
            except PermissionError:
                break
    print(disk.name, "readable size:", disk_size)

对于两个不同的32GB SD卡,我得到以下结果:

\\.\PHYSICALDRIVE2 reported size: 31683778560
\\.\PHYSICALDRIVE2 readable size: 31691110400
\\.\PHYSICALDRIVE3 reported size: 31437020160
\\.\PHYSICALDRIVE3 readable size: 31439453184

然而,实际的驱动器实际上还有1024到2048个字节,我们仍然无法读取,而且我不知道如何获取它们。但是,这比我们之前缺少的几MB好。

编辑:似乎buffering导致了读取最后几个字节的问题。如果我open(disk.name, "rb", buffering=0),我可以读取剩余的字节。然而,这非常慢(约1MB /秒,相当于其中一个驱动器约7秒)。这可能是一个很好的混合方法,你只使用buffering = 0来读取最后几个字节,并在其余时间使用默认缓冲。

\\.\PHYSICALDRIVE2 reported size: 31683778560
\\.\PHYSICALDRIVE2 readable size: 31691112448 (with buffering=0)
\\.\PHYSICALDRIVE14 reported size: 31437020160
\\.\PHYSICALDRIVE14 readable size: 31439454208 (with buffering=0)

编辑2 :您可以使用read1获取最后几个字节,而无需使用buffering=0打开文件。因此,要获得实际的磁盘大小,您可以这样做:

reported_size = disk.size
f.seek(reported_size)
while True:
    try:  # Read beyond the reported size
        f.read(sector_size)
    except PermissionError:
        easily_readable_size = f.tell()
        try:  # Get the last few bytes using read1 (unbuffered)
            for i in range(128):  # Test up to this many additional sectors
                f.read1(self.sector_size)
        except PermissionError:
            actual_size = f.tell()
            break

注意我认为您可能无法始终f.read最多easily_readable_size,因为内部缓冲区的对齐可能并不总是相同(?)。我将该值减少io.DEFAULT_BUFFER_SIZE以使其更安全一些。然后我用我自己的函数覆盖了f.read,该函数在整个磁盘上正确地f.read透明地f.read组合了上述内容。这样,{{1}}就会起到预期它首先发挥作用的作用。

答案 1 :(得分:0)

你说这个片段不能用于特定的硬盘吗?你能告诉我们这个硬盘的细节以及你怎么知道它是不正确的。

但是,请尝试使用纯winapi方法。 DeviceIoControl可用于舒适地。请参阅cpp。中的complete code listing

我知道有一种方法可以在python中编写c ++,这样就可以了。)

答案 2 :(得分:0)

我在使用用户 user3268002 的读取测试解决方案时遇到问题。使用可正常工作的 USB 闪存驱动器,它导致了整整一分钟的冻结,在此期间还使其他应用程序无法访问驱动器列表,甚至一度导致驱动器在重新插入之前无法再访问。根据初始查找位置,报告的大小也不正确,报告太多字节(扇区),因为第一个 read() 调用愉快地读取了末尾之外的几个扇区,无一例外。但它适用于普通硬盘。

以下代码始终为我提供了 HxD 报告的所有测试驱动器的正确大小。

import struct
import win32file  #pip install pywin32
import winioctlcon #pip install pywin32

f = win32file.CreateFile('\\\\.\\PHYSICALDRIVE0', win32file.GENERIC_READ, 0, None, win32file.OPEN_EXISTING, win32file.FILE_ATTRIBUTE_NORMAL, 0)
size = win32file.DeviceIoControl(f, winioctlcon.IOCTL_DISK_GET_LENGTH_INFO, None, 512, None)  #returns bytes
size = struct.unpack('q', size)[0]  #convert 64 bit int from bytes to int -> first element of returned tuple
print(size)
f.close()