Есть ли способ перечислить все доступные диски Windows?

Есть ли способ в Python перечислить все буквы дисков, которые используются в настоящее время в системе Windows?

(Кажется, мой гугл-фу меня подвел)

C++ эквивалент: Перечисление всех доступных букв дисков в Windows


person Electrons_Ahoy    schedule 05.05.2009    source источник


Ответы (17)


import win32api

drives = win32api.GetLogicalDriveStrings()
drives = drives.split('\000')[:-1]
print drives

По материалам: http://www.faqts.com/knowledge_base/view.phtml/aid/4670

person Ayman Hourieh    schedule 05.05.2009
comment
Я просто попробовал это в версии 2.6, и в конце получил лишнюю пустую строку. Тем не менее хороший ответ. - person Mark Ransom; 05.06.2009
comment
Чтобы убедиться, что вы не отбрасываете непустые строки, рассмотрите возможность использования drives = [drivestr in drives.split('\000') if drivestr] - person Wesley; 27.03.2010
comment
Это также возвращает виртуальный привод компакт-дисков в результате. Полагаю, было бы неплохо проверить, действителен ли путь или нет. - person kittenparry; 30.07.2020
comment
Мне пришлось запустить pip install pypiwin32 как администратор, прежде чем я смог использовать import win32api. - person user42723; 11.08.2020

Без использования каких-либо внешних библиотек, если это важно для вас:

import string
from ctypes import windll

def get_drives():
    drives = []
    bitmask = windll.kernel32.GetLogicalDrives()
    for letter in string.uppercase:
        if bitmask & 1:
            drives.append(letter)
        bitmask >>= 1

    return drives

if __name__ == '__main__':
    print get_drives()     # On my PC, this prints ['A', 'C', 'D', 'F', 'H']
person RichieHindle    schedule 05.05.2009
comment
Есть ли причина не использовать string.lowercase или string.ascii_lowercase вместо string.letters [len (string.letters) / 2:]? - person John Fouhy; 06.05.2009
comment
@John: Нет причин - спасибо за предложение, теперь изменено на string.uppercase (потому что для букв дисков я предпочитаю заглавные, не знаю, почему 8-) - person RichieHindle; 06.05.2009
comment
[c + ': \\' вместо c в string.lowercase, если os.path.isdir (c + ': \\')] - person Berry Tsakala; 05.06.2009
comment
Берри: это вызовет неприятные диалоговые окна Windows, если у вас есть съемные носители без носителей ... - person Ted Mielczarek; 30.06.2010
comment
На момент написания этого вопроса этому вопросу 4 года, поэтому, по-видимому, этот ответ предназначен для совместимости со старой версией Python. Я хотел бы добиться того, что OP запрашивает с 2.7, в частности, без внешней библиотеки, если это возможно, но GetLogicalDrives (), похоже, не существует, по крайней мере, для версии, которую я использую ... - person RTF; 02.09.2013
comment
@RTF: у меня это работает с Python 2.7 (32 бит) - какая ошибка возникает при попытке его запустить? - person RichieHindle; 02.09.2013
comment
К сожалению, я сейчас занимаюсь разработкой под Linux, и, согласно Eclipse, GetLogicalDrives (класс?) Не существует. Кроме того, windll вызывает ошибку импорта в интерактивном питоне, но не в Eclipse. Мое приложение многоплатформенное, но я еще не начал тестировать в Windows. Будет ли windll доступен только с Pythons Windows dist, и если да, то почему Eclipse распознает импорт? - person RTF; 02.09.2013
comment
Извините, у меня тоже отлично работает в Windows с 2.7 - person RTF; 02.09.2013
comment
Этот код не имеет смысла в Linux. GetLogicalDrives() - это Windows API. Понятия логических дисков (C :, D: и т. Д.) В Linux не существует. Я не знаю, что делает Eclipse. - person RichieHindle; 02.09.2013
comment
Спасибо. Это отличное решение. Я обернул его: #import platform; если platform.uname [0] == 'Windows': - person SoloPilot; 13.11.2014
comment
что, если я хочу также получить имя Диска? - person PNC; 16.10.2017

Нашел это решение в Google, немного измененное по сравнению с оригиналом. Выглядит довольно питонично и не нуждается в "экзотическом" импорте.

import os, string
available_drives = ['%s:' % d for d in string.ascii_uppercase if os.path.exists('%s:' % d)]
person Barmaley    schedule 09.12.2015
comment
FWIW это не удалось для меня по крайней мере один раз по неизвестной причине - person NirIzr; 20.09.2017
comment
Это собственно доступ к дискам, так что не совсем то же самое - person debuti; 23.02.2021

Это похоже на лучшие ответы. Вот моя хакерская фигня

import os, re
re.findall(r"[A-Z]+:.*$",os.popen("mountvol /").read(),re.MULTILINE)

Немного ошибся в ответе RichieHindle; это не совсем лучше, но вы можете заставить окна делать работу по придумыванию букв алфавита

>>> import ctypes
>>> buff_size = ctypes.windll.kernel32.GetLogicalDriveStringsW(0,None)
>>> buff = ctypes.create_string_buffer(buff_size*2)
>>> ctypes.windll.kernel32.GetLogicalDriveStringsW(buff_size,buff)
8
>>> filter(None, buff.raw.decode('utf-16-le').split(u'\0'))
[u'C:\\', u'D:\\']
person SingleNegationElimination    schedule 06.05.2009
comment
Мне нравится это решение. Удобно не использовать win32api. - person WorldDominator; 07.04.2015
comment
@SebastianHietsch: Пожалуйста, задайте новый вопрос. - person SingleNegationElimination; 12.06.2016
comment
У меня не работает на Windows 8, Python 3.5.2. Получает диск C, но не получает диск Z. - person wjandrea; 16.02.2017
comment
mountvol /, похоже, ничего не делает, кроме как выдавать информацию об использовании команды в Windows 7 или 10 ... - person ArtOfWarfare; 18.03.2018

Microsoft Script Repository включает этот рецепт, который может помочь. Однако у меня нет компьютера с Windows, чтобы проверить это, поэтому я не уверен, хотите ли вы «Имя», «Имя системы», «Имя тома» или, может быть, что-то еще.

import win32com.client 
strComputer = "." 
objWMIService = win32com.client.Dispatch("WbemScripting.SWbemLocator") 
objSWbemServices = objWMIService.ConnectServer(strComputer,"root\cimv2") 
colItems = objSWbemServices.ExecQuery("Select * from Win32_LogicalDisk") 
for objItem in colItems: 
    print "Access: ", objItem.Access 
    print "Availability: ", objItem.Availability 
    print "Block Size: ", objItem.BlockSize 
    print "Caption: ", objItem.Caption 
    print "Compressed: ", objItem.Compressed 
    print "Config Manager Error Code: ", objItem.ConfigManagerErrorCode 
    print "Config Manager User Config: ", objItem.ConfigManagerUserConfig 
    print "Creation Class Name: ", objItem.CreationClassName 
    print "Description: ", objItem.Description 
    print "Device ID: ", objItem.DeviceID 
    print "Drive Type: ", objItem.DriveType 
    print "Error Cleared: ", objItem.ErrorCleared 
    print "Error Description: ", objItem.ErrorDescription 
    print "Error Methodology: ", objItem.ErrorMethodology 
    print "File System: ", objItem.FileSystem 
    print "Free Space: ", objItem.FreeSpace 
    print "Install Date: ", objItem.InstallDate 
    print "Last Error Code: ", objItem.LastErrorCode 
    print "Maximum Component Length: ", objItem.MaximumComponentLength 
    print "Media Type: ", objItem.MediaType 
    print "Name: ", objItem.Name 
    print "Number Of Blocks: ", objItem.NumberOfBlocks 
    print "PNP Device ID: ", objItem.PNPDeviceID 
    z = objItem.PowerManagementCapabilities 
    if z is None: 
        a = 1 
    else: 
        for x in z: 
            print "Power Management Capabilities: ", x 
    print "Power Management Supported: ", objItem.PowerManagementSupported 
    print "Provider Name: ", objItem.ProviderName 
    print "Purpose: ", objItem.Purpose 
    print "Quotas Disabled: ", objItem.QuotasDisabled 
    print "Quotas Incomplete: ", objItem.QuotasIncomplete 
    print "Quotas Rebuilding: ", objItem.QuotasRebuilding 
    print "Size: ", objItem.Size 
    print "Status: ", objItem.Status 
    print "Status Info: ", objItem.StatusInfo 
    print "Supports Disk Quotas: ", objItem.SupportsDiskQuotas 
    print "Supports File-Based Compression: ", objItem.SupportsFileBasedCompression 
    print "System Creation Class Name: ", objItem.SystemCreationClassName 
    print "System Name: ", objItem.SystemName 
    print "Volume Dirty: ", objItem.VolumeDirty 
    print "Volume Name: ", objItem.VolumeName 
    print "Volume Serial Number: ", objItem.VolumeSerialNumber 
person John Fouhy    schedule 06.05.2009
comment
Спасибо за ссылку на Microsoft Script Repository. - person Konstantin Tenzin; 15.05.2009
comment
Мне всегда казалось, что это отличный ресурс для программистов Windows, который недостаточно широко известен :-) - person John Fouhy; 18.05.2009
comment
Еще один +1 за ссылку на репозиторий скриптов Microsoft, о котором я никогда раньше не слышал. - person Mark Ransom; 05.06.2009
comment
Ссылка мертва, поэтому вот ее сохраненная версия с WayBackMachine: https://web.archive.org/web/20090626062333/http://www.microsoft.com/technet/scriptcenter/scripts/python/storage/disks/drives/stdvpy05.mspx - person Enkouyami; 10.03.2019
comment
Спасибо @Enkouyami, похоже, Microsoft не уничтожила контент, а только переместила его. Я поискал и нашел рабочую ссылку. - person John Fouhy; 11.03.2019

Я написал этот фрагмент кода:

import os
drives = [ chr(x) + ":" for x in range(65,91) if os.path.exists(chr(x) + ":") ]

Он основан на ответе @Barmaley, но имеет то преимущество, что не использует модуль string, если вы не хотите его использовать. Он также работает в моей системе, в отличие от ответа @ SingleNegationElimination.

person Sebastian Hietsch    schedule 11.06.2016
comment
Здесь нуб Python! Почему x находится в диапазоне (65,90)? Как именно это работает? Некоторое объяснение было бы полезно для таких людей, как я. Заранее спасибо! - person Amar; 19.08.2020
comment
Коды ASCII с 65 по 90 соответствуют буквам A-Z. Скрипт проверяет все возможные обозначения дисков (от A: до Z :) и, если они есть, добавляются в список. - person Sebastian Hietsch; 24.08.2020
comment
Я изменил его на диапазон (65,91), потому что он не включал Z: в исходной версии. - person Sebastian Hietsch; 24.08.2020

Вот еще одно отличное решение, если вы хотите перечислить только диски на вашем диске, а не подключенные сетевые диски. Если вы хотите фильтровать по разным атрибутам, просто распечатайте drps.

import psutil
drps = psutil.disk_partitions()
drives = [dp.device for dp in drps if dp.fstype == 'NTFS']
person PythonMan    schedule 04.12.2018

Более оптимальное решение на основе @RichieHindle

def get_drives():
    drives = []
    bitmask = windll.kernel32.GetLogicalDrives()
    letter = ord('A')
    while bitmask > 0:
        if bitmask & 1:
            drives.append(chr(letter) + ':\\')
        bitmask >>= 1
        letter += 1

    return drives
person tiredgin    schedule 26.07.2016

В Windows вы можете сделать os.popen

import os
print os.popen("fsutil fsinfo drives").readlines()
person user2015144    schedule 08.09.2017
comment
Решение только для администратора - person pstatix; 22.12.2017

вот более простая версия, без установки каких-либо дополнительных модулей или каких-либо функций. Поскольку буквы дисков не могут выходить за рамки A и Z, вы можете выполнить поиск, есть ли путь для каждого алфавита, как показано ниже:

>>> import os
>>> for drive_letter in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ':
        if os.path.exists(f'{drive_letter}:'):
            print(f'{drive_letter}:')
        else:
            pass

однострочный:

>>> import os
>>> [f'{d}:' for d in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' if os.path.exists(f'{d}:')]
['C:', 'D:']
person Naveen Reddy Marthala    schedule 25.11.2019
comment
Здесь нуб Python! Я предполагаю, что "% s:" - это что-то вроде регулярного выражения, но я не уверен. Некоторое объяснение того, как этот код действительно работает, было бы неплохо для улучшения моего понимания. Заранее спасибо! - person Amar; 19.08.2020
comment
нет,% s не является регулярным выражением. это средство форматирования строк. проверьте мою новую правку с помощью f-строк. - person Naveen Reddy Marthala; 19.08.2020

Вот мой подход с более высокой производительностью (возможно, и выше):

>>> from string import ascii_uppercase
>>> reverse_alphabet = ascii_uppercase[::-1]
>>> from ctypes import windll # Windows only
>>> GLD = windll.kernel32.GetLogicalDisk
>>> drives = ['%s:/'%reverse_alphabet[i] for i,v in enumerate(bin(GLD())[2:]) if v=='1']

Никто на самом деле не использует перформативную функциональность Python ...

Да, я не следую соглашениям о стандартных путях Windows ('\\') ...
За все годы использования python у меня не было проблем с '/' везде, где используются пути, и я сделал это стандарт в моих программах.

person Tcll    schedule 28.11.2016

Этот код вернет список управляемых имен и букв, например:

['Шлюз (C :)', 'EOS_DIGITAL (L :)', 'Музыкальный архив (O :)']

Он использует только стандартную библиотеку. Он основан на нескольких идеях, которые я нашел выше. windll.kernel32.GetVolumeInformationW () возвращает 0, если дисковод пуст, например, компакт-диск без диска. Этот код не перечисляет эти пустые диски.

В этих двух строках записаны буквы всех дисков:

bitmask = (bin(windll.kernel32.GetLogicalDrives())[2:])[::-1]  # strip off leading 0b and reverse
drive_letters = [ascii_uppercase[i] + ':/' for i, v in enumerate(bitmask) if v == '1']

Вот полный порядок действий:

from ctypes import windll, create_unicode_buffer, c_wchar_p, sizeof
from string import ascii_uppercase

def get_win_drive_names():
    volumeNameBuffer = create_unicode_buffer(1024)
    fileSystemNameBuffer = create_unicode_buffer(1024)
    serial_number = None
    max_component_length = None
    file_system_flags = None
    drive_names = []
    #  Get the drive letters, then use the letters to get the drive names
    bitmask = (bin(windll.kernel32.GetLogicalDrives())[2:])[::-1]  # strip off leading 0b and reverse
    drive_letters = [ascii_uppercase[i] + ':/' for i, v in enumerate(bitmask) if v == '1']

    for d in drive_letters:
        rc = windll.kernel32.GetVolumeInformationW(c_wchar_p(d), volumeNameBuffer, sizeof(volumeNameBuffer),
                                                   serial_number, max_component_length, file_system_flags,
                                                   fileSystemNameBuffer, sizeof(fileSystemNameBuffer))
        if rc:
            drive_names.append(f'{volumeNameBuffer.value}({d[:2]})')  # disk_name(C:)
    return drive_names
person EGarbus    schedule 04.06.2019

Это поможет найти действующие диски в ОС Windows.

import os
import string
drive = string.ascii_uppercase
valid_drives = []
for each_drive in drive:
    if os.path.exist(each_drive+":\\"):
       print(each_drive)
       valid_drives.append(each_drive+":\\")
print(valid_drives)

Выход будет

C
D
E
['C:\\','D:\\','E:\\']
person Jobin James    schedule 08.07.2020

Поскольку у меня на ноутбуках не установлен win32api, я использовал это решение с помощью wmic:

import subprocess
import string

#define alphabet
alphabet = []
for i in string.ascii_uppercase:
    alphabet.append(i + ':')

#get letters that are mounted somewhere
mounted_letters = subprocess.Popen("wmic logicaldisk get name", shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
#erase mounted letters from alphabet in nested loop
for line in mounted_letters.stdout.readlines():
    if "Name" in line:
        continue
    for letter in alphabet:
        if letter in line:
            print 'Deleting letter %s from free alphabet %s' % letter
            alphabet.pop(alphabet.index(letter))

print alphabet

в качестве альтернативы вы можете получить разницу из обоих списков, например, это более простое решение (после запуска подпроцесса wmic как монтированные_letters):

#get output to list
mounted_letters_list = []
for line in mounted_letters.stdout.readlines():
    if "Name" in line:
        continue
    mounted_letters_list.append(line.strip())

rest = list(set(alphabet) - set(mounted_letters_list))
rest.sort()
print rest

оба решения одинаково быстрые, но я думаю, что по какой-то причине сет-лист лучше, не так ли?

person Pulec    schedule 02.05.2014

В рамках аналогичной задачи мне также нужно было получить бесплатную букву диска. Я решил, что хочу максимально возможное письмо. Сначала я написал его более идиоматично, а затем сжал до однострочника, чтобы посмотреть, имеет ли он смысл. Как ни круто понимание списков, я люблю сеты для этого: unused=set(alphabet)-set(used) вместо того, чтобы делать unused = [a for a in aphabet if a not in used]. Крутая вещь!

def get_used_drive_letters():
    drives = win32api.GetLogicalDriveStrings()
    drives = drives.split('\000')[:-1]
    letters = [d[0] for d in drives]
    return letters

def get_unused_drive_letters():
    alphabet = map(chr, range(ord('A'), ord('Z')+1))
    used = get_used_drive_letters()
    unused = list(set(alphabet)-set(used))
    return unused

def get_highest_unused_drive_letter():
    unused = get_unused_drive_letters()
    highest = list(reversed(sorted(unused)))[0]
    return highest

Один лайнер:

def get_drive():
    highest = sorted(list(set(map(chr, range(ord('A'), ord('Z')+1))) -
                          set(win32api.GetLogicalDriveStrings().split(':\\\000')[:-1])))[-1]

Я также выбрал алфавит с помощью map / range / ord / chr вместо использования строки, поскольку части строки устарели.

person flutefreak7    schedule 09.09.2014

если вы не хотите беспокоиться о кроссплатформенных проблемах, в том числе о проблемах на платформах Python, таких как Pypy, и хотите, чтобы при обновлении дисков во время выполнения использовалось что-то прилично производительное:

>>> from os.path import exists
>>> from sys import platform
>>> drives = ''.join( l for l in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' if exists('%s:/'%l) ) if platform=='win32' else ''
>>> drives
'CZ'

вот мой тест производительности этого кода:

4000 iterations; threshold of min + 250ns:
__________________________________________________________________________________________________________code___|_______min______|_______max______|_______avg______|_efficiency
⡇⠀⠀⢀⠀⠀⠀⠀⠀⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⣷⣷⣶⣼⣶⣴⣴⣤⣤⣧⣤⣤⣠⣠⣤⣤⣶⣤⣤⣄⣠⣦⣤⣠⣤⣤⣤⣤⣄⣠⣤⣠⣤⣤⣠⣤⣤⣤⣤⣤⣤⣄⣤⣤⣄⣤⣄⣤⣠⣀⣀⣤⣄⣤⢀⣀⢀⣠⣠⣀⣀⣤⣀⣠
    drives = ''.join( l for l in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' if exists('%s:/'%l) ) if platform=='win32' else '' |      290.049ns |     1975.975ns |      349.911ns |  82.892%
person Tcll    schedule 11.03.2018

Если вам нужны только буквы для каждого диска, вы можете просто:

from win32.win32api import GetLogicalDriveStrings


drives = [drive for drive in GetLogicalDriveStrings()[0]]
person 1schware    schedule 19.09.2020