开发者

In Python, how do I check if a drive exists w/o throwing an error for removable drives?

Here's what I have so far:

import os.path as op
for d in map(chr, range(98, 123)): #drives b-z
    开发者_如何学Goif not op.isdir(d + ':/'): continue

The problem is that it pops up a "No Disk" error box in Windows:

maya.exe - No Disk: There is no disk in the drive. Please insert a disk into drive \Device\Harddisk1\DR1 [Cancel, Try Again, Continue]

I can't catch the exception because it doesn't actually throw a Python error.

Apparently, this only happens on removable drives where there is a letter assigned, but no drive inserted.

Is there a way to get around this issue without specifically telling the script which drives to skip?

In my scenario, I'm at the school labs where the drive letters change depending on which lab computer I'm at. Also, I have zero security privileges to access disk management.


Use the ctypes package to access the GetLogicalDrives function. This does not require external libraries such as pywin32, so it's portable, although it is a little clunkier to work with. For example:

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 was added in Python 2.7 and 3.1; if you need to support <2.7 or <3.1, here's an implementation of that function:

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


Here's a way that works both on Windows and Linux, for both Python 2 and 3:

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


If you have the win32file module, you can call GetLogicalDrives():

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


To disable the error popup, you need to set the SEM_FAILCRITICALERRORS Windows error flag using pywin:

old_mode = win32api.SetErrorMode(0)
SEM_FAILCRITICALERRORS = 1 # not provided by PyWin, last I checked
win32api.SetErrorMode(old_mode & 1)

This tells Win32 not to show the retry dialog; when an error happens, it's returned to the application immediately.

Note that this is what Python calls are supposed to do. In principle, Python should be setting this flag for you. Unfortunately, since Python may be embedded in another program, it can't change process-wide flags like that, and Win32 has no way to specify this flag in a way that only affects Python and not the rest of the code.


import os

possible_drives_list = [chr(97 + num).upper() for num in range(26)]

for drive in possible_drives_list:
    print(drive + ' exists :' + str(os.path.exists(drive + ':\\')))


import os 
def IsDriveExists(drive):
    return os.path.exists(drive + ':\\')
    
print(IsDriveExists('c')) 
print(IsDriveExists('d'))
print(IsDriveExists('e'))
print(IsDriveExists('x'))
print(IsDriveExists('v'))

this works in any os


As long as a little parsing is acceptable, this is one way to do it without installing win32api and without iterating through all possible drive letters.

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('\n'):
        if line:
            lineSplit = line.split(',')
            if len(lineSplit) == 4 and lineSplit[1][1] == ':':
                results.append(lineSplit[1][0])
    return results

You could also parse for specific drive types, such as "Network Connection" to get a list of all network mounted drive letters by adding and lineSplit[2] == 'Network Connection' for example.

Alternatively, rather than returning a list, you could return a dictionary, where keys are drive letters and values are unc paths (lineSplit[3]). Or whatever other info you want to pull from wmic. To see more options: wmic logicaldisk get /?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜