【问题标题】:Is there a way to list all the available Windows' drives?有没有办法列出所有可用的 Windows 驱动器?
【发布时间】:2009-05-05 23:23:47
【问题描述】:

有没有办法在 Python 中列出 Windows 系统中所有当前正在使用的驱动器号?

(我的 Google-fu 似乎让我失望了)

C++ 等效项:Enumerating all available drive letters in Windows

【问题讨论】:

    标签: python windows


    【解决方案1】:
    import win32api
    
    drives = win32api.GetLogicalDriveStrings()
    drives = drives.split('\000')[:-1]
    print drives
    

    改编自: http://www.faqts.com/knowledge_base/view.phtml/aid/4670

    【讨论】:

    • 我刚刚在 2.6 中尝试过,最后得到了一个额外的空字符串。仍然是一个很好的答案。
    • 只是为了确保您不会丢弃任何非空字符串,请考虑使用drives = [drivestr in drives.split('\000') if drivestr]
    • 这也会返回虚拟 CD 驱动器。我想检查路径是否有效可能是个好主意。
    • 我必须以管理员身份运行 pip install pypiwin32 才能使用 import win32api
    【解决方案2】:

    不使用任何外部库,如果这对您很重要:

    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']
    

    【讨论】:

    • 有什么理由不使用 string.lowercase 或 string.ascii_lowercase 代替 string.letters[len(string.letters)/2:] ?
    • @John:没有理由 - 感谢您的建议,现在改为 string.uppercase(因为驱动器号我更喜欢大写字母,不知道为什么 8-)
    • [c+':\\' for c in string.lowercase if os.path.isdir(c+':\\')]
    • Berry:如果您的可移动媒体驱动器中没有媒体,则会弹出令人讨厌的 Windows 对话框...
    • 这段代码在 Linux 上毫无意义。 GetLogicalDrives() 是一个 Windows API。 Linux 上不存在逻辑驱动器(C:、D: 等)的概念。我不知道 Eclipse 在做什么。
    【解决方案3】:

    在 Google 上找到了这个解决方案,对原始版本稍作修改。看起来很pythonic,不需要任何“异国情调”的进口

    import os, string
    available_drives = ['%s:' % d for d in string.ascii_uppercase if os.path.exists('%s:' % d)]
    

    【讨论】:

    • FWIW 这对我来说至少失败了一次,原因不明
    • 这实际上是访问驱动器,所以不完全一样
    【解决方案4】:

    我写了这段代码:

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

    它基于@Barmaley 的回答,但具有不使用string 的优势 模块,以防您不想使用它。与@SingleNegationElimination 的回答不同,它也适用于我的系统。

    【讨论】:

    • 这里有一个 Python 菜鸟!为什么“x in range(65,90)”?这究竟是如何工作的?一些解释对像我这样的人很有用。提前谢谢!
    • ASCII 码 65 到 90 对应字母 A-Z。该脚本检查所有可能的驱动器名称(从 A: 到 Z:),如果存在,则将它们添加到列表中。
    • 我将其更改为 range(65,91),因为它在原始版本中不包含 Z:。
    【解决方案5】:

    这些看起来是更好的答案。这是我的恶作剧

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

    RichieHindle 的回答稍作修改;它并不是真的更好,但你可以让 windows 来完成提出实际字母的工作

    >>> 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:\\']
    

    【讨论】:

    • 我喜欢这个解决方案。方便不用win32api。
    • UnicodeDecodeError: 'charmap' codec can't decode byte 0x81 in position 586: character maps to <undefined>
    • @SebastianHietsch:请提出一个新问题。
    • 在 Windows 8、Python 3.5.2 上对我不起作用。获得 C 盘,但没有获得 Z 盘。
    • mountvol / 除了在 Windows 7 或 10 上吐出命令的使用信息外,似乎什么也没做...
    【解决方案6】:

    Microsoft Script Repository 包括 this recipe,这可能会有所帮助。不过,我没有 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 
    

    【讨论】:

    • 感谢您提供指向 Microsoft Script Repository 的链接。
    • 我一直觉得它是 Windows 程序员的绝佳资源,但知名度还不够高:-)
    • Microsoft 脚本存储库链接的另一个 +1,我以前从未听说过。
    • 链接已失效,所以这是来自 WayBackMachine 的保存版本:web.archive.org/web/20090626062333/http://www.microsoft.com/…
    • 感谢@Enkouyami,看起来微软并没有杀死内容,只是移动了它。我四处寻找,找到了一个有效的链接。
    【解决方案7】:

    如果您只想列出磁盘上的驱动器而不列出映射的网络驱动器,这是另一个很好的解决方案。如果您想按不同的属性进行过滤,只需打印 drps。

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

    【讨论】:

      【解决方案8】:

      在 Windows 上你可以做一个 os.popen

      import os
      print os.popen("fsutil fsinfo drives").readlines()
      

      【讨论】:

      • 虽然只有管理员解决方案
      【解决方案9】:

      基于@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
      

      【讨论】:

        【解决方案10】:

        这是一个更简单的版本,无需安装任何额外的模块或任何功能。由于驱动器号不能超出 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:']
        

        【讨论】:

        • 这里有一个 Python 菜鸟!我猜 '%s:' 类似于正则表达式,但我不确定。关于这段代码如何真正工作的一些解释,会很好地提高我的理解。提前谢谢!
        • 不,%s 不是正则表达式。它是一个字符串格式化程序。使用 f-strings 检查我的新编辑。
        【解决方案11】:

        这是我的更高性能的方法(可能会更高):

        >>> 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 的这些年里,我在任何使用路径的地方都没有遇到任何问题,并且在我的程序中使它成为标准。

        【讨论】:

          【解决方案12】:

          此代码将返回驱动器名称和字母列表,例如:

          ['Gateway(C:)', 'EOS_DIGITAL(L:)', 'Music Archive(O:)']

          它只使用标准库。它建立在我上面发现的一些想法之上。 如果磁盘驱动器为空,例如没有磁盘的 CD ROM,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
          

          【讨论】:

            【解决方案13】:

            这将有助于在 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:\\']
            

            【讨论】:

              【解决方案14】:

              如果您只需要每个驱动器的字母,您可以:

              from win32.win32api import GetLogicalDriveStrings
              
              
              drives = [drive for drive in GetLogicalDriveStrings()[0]]
              

              【讨论】:

                【解决方案15】:

                由于我的笔记本领域没有安装 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 子进程作为mounted_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
                

                这两种解决方案都同样快,但我想 set list 出于某种原因更好,对吧?

                【讨论】:

                  【解决方案16】:

                  作为类似任务的一部分,我还需要获取一个空闲驱动器号。我决定我想要最高可用的字母。我首先用更惯用的方式把它写出来,然后把它压缩成一个 1-liner,看看它是否仍然有意义。和列表推导一样棒,我喜欢这个集合: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 而不是使用字符串的字母表,因为部分字符串已被弃用。

                  【讨论】:

                    【解决方案17】:

                    如果您不想担心跨平台问题,包括跨 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%
                    

                    【讨论】:

                      猜你喜欢
                      • 2021-12-30
                      • 2013-02-27
                      • 2020-03-28
                      • 2014-03-28
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2012-01-12
                      相关资源
                      最近更新 更多