WMI сообщает, что диски на несколько МБ меньше, чем они есть на самом деле.Я думаю, что это связано с тем, как 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)
Я получаю следующий результат для двух разных 32 ГБ SD-карт:
\\.\PHYSICALDRIVE2 reported size: 31683778560
\\.\PHYSICALDRIVE2 readable size: 31691110400
\\.\PHYSICALDRIVE3 reported size: 31437020160
\\.\PHYSICALDRIVE3 readable size: 31439453184
Однако на реальных дисках фактически есть дополнительные 1024–2048 байтов, которые мы до сих пор не можем прочитать, и я 'Я не уверен, как их получить.Однако это лучше, чем несколько МБ, которые мы пропускали раньше.
Редактировать: Похоже, что буферизация вызывала проблему с чтением последних нескольких байтов.Я могу прочитать оставшиеся байты, если я сделаю open(disk.name, "rb", buffering=0)
.Однако это было очень медленно (~ 1 МБ / с, что составляет около 7 секунд для одного из дисков).Вероятно, есть хороший гибридный подход, в котором вы используете только буферизацию = 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
работает так, как вы ожидаете, что он будет работать в первую очередь.