windows - Hvordan kontrollerer jeg i Python, om der eksisterer et drev uden at kaste en fejl for flytbare drev?

Indlæg af Hanne Mølgaard Plasc

Problem



Her er hvad jeg har hidtil:


import os.path as op
for d in map(chr, range(98, 123)): #drives b-z
    if not op.isdir(d + ':/'): continue


Problemet er, at det vises et fejlfelt 'No Disk' i Windows:



  maya.exe - Ingen disk: Der er ingen disk i
  køreturen. Indsæt venligst en disk i
  drive \ Device \ Harddisk1 \ DR1 [[Annuller, prøv igen, fortsæt]]



Jeg kan ikke tage undtagelsen, fordi den ikke kaster en Python-fejl.


Dette sker tilsyneladende kun på flytbare drev, hvor der er tildelt et brev, men der er ikke indsat noget drev.


Er der en måde at omgå dette problem uden specifikt at fortælle scriptet, der kører for at springe over?


I mit scenario er jeg på skolelaboratorierne, hvor drevbogstaverne ændres afhængigt af hvilken laboratoriecomputer jeg er på. Jeg har også nul sikkerhedsrettigheder for at få adgang til diskhåndtering.

Bedste reference


Brug pakken ctypes for at få adgang til GetLogicalDrives -funktionen. Dette kræver ikke eksterne biblioteker som pywin32, så det er bærbart, selvom det er lidt klunkere at arbejde med. For eksempel: [16] [17]


import ctypes
import itertools
import os
import string
import platform

def get\_available\_drives():
    if 'Windows' not in platform.system():
        return []
    drive\_bitmask = ctypes.cdll.kernel32.GetLogicalDrives()
    return list(itertools.compress(string.ascii\_uppercase,
               map(lambda x:ord(x) - ord('0'), bin(drive\_bitmask)[:1:-1])))


itertools.compress blev tilsat i Python 2.7 og 3.1; hvis du har brug for at understøtte < 2.7 eller < 3.1, her er en implementering af den funktion:


def compress(data, selectors):
    for d, s in zip(data, selectors):
        if s:
            yield d

Andre referencer 1


Hvis du har Win32file-modulet, kan du ringe til GetLogicalDrives (): [18] [19]


def does\_drive\_exist(letter):
    import win32file
    return (win32file.GetLogicalDrives() >> (ord(letter.upper()) - 65) & 1) != 0

Andre referencer 2


For at deaktivere fejl popup, skal du indstille SEM\_FAILCRITICALERRORS Windows fejlflag ved hjælp af pywin:


old\_mode = win32api.SetErrorMode(0)
SEM\_FAILCRITICALERRORS = 1 # not provided by PyWin, last I checked
win32api.SetErrorMode(old\_mode & 1)


Dette fortæller Win32, at man ikke viser dialogboksen for genoptryk. Når en fejl opstår, returneres den straks til ansøgningen.


Bemærk, at dette er, hvad Python-opkald er formodes at gøre. Python bør i princippet indstille dette flag til dig. Desværre, da Python kan være indlejret i et andet program, kan det ikke ændre process-wide flag, sådan, og Win32 har ingen måde at angive dette flag på en måde, der kun påvirker Python og ikke resten af ​​koden.

Andre referencer 3


Her er en måde, der fungerer både på Windows og Linux, for både Python 2 og 3:


import platform,os
def hasdrive(letter):
    return "Windows" in platform.system() and os.system("vol \%s: 2>nul>nul" \% (letter)) == 0

Andre referencer 4


Så længe en lille parsing er acceptabel, er det en måde at gøre det uden at installere win32api og uden at iterere gennem alle mulige drevbogstaver.


from subprocess import check\_output
def getDriveLetters():
    args = [
        'wmic',
        'logicaldisk',
        'get',
        'caption,description,providername',
        '/format:csv'
    ]
    output = check\_output(args)
    results = list()
    for line in  output.split('
'):
        if line:
            lineSplit = line.split(',')
            if len(lineSplit) == 4 and lineSplit[1][1] == ':':
                results.append(lineSplit[1][0])
    return results


Du kan også analysere for bestemte drevtyper, f.eks. 'Netværksforbindelse' for at få en liste over alle netværksmonterede drevbreve ved at tilføje and lineSplit[2] == 'Network Connection' for eksempel.


Alternativt kan du i stedet for at returnere en liste returnere en ordbog, hvor nøgler er drevbogstaver og værdier er ukendte stier (lineSplit[3]). Eller hvad andre oplysninger du vil trække fra wmic. For at se flere muligheder: wmic logicaldisk get /?