Is there a simple way to get the "real" case sensitive path from a all lower case path. Like the reverse of os.path.normcase.
For example, consider the directory:
c:\StackOverFlow
If I have the following snippet, how to obtain 开发者_Go百科d_real?
>>> import os
>>> d = os.path.normcase('C:\\StackOverFlow') # convert to lower case
>>> d
'c:\\stackoverflow'
>>> d_real = ... # should give 'C:\StackOverFlow' with the correct case
I wouldn't consider this solution simple, but what you can to is:
import os
d = os.path.normcase('C:\\StackOverFlow')
files = os.listdir(os.path.dirname(d))
for f in files:
if not d.endswith(f.lower()):
continue
else
real_d = os.path.join(os.path.dirname(d), f)
It's probably not efficient (depending on the number of files in the directory). It needs tweaking for the path-components (my solution really only corrects the case of the file name and doesn't care about the directory names). Also, maybe os.walk
could be helpful to traverse down the tree.
You can do this by chaining GetShortPathName
and GetLongPathName
. This can in theory not work because you can disable short filenames on Windows with some configuration setting. Here's some sample code using ctypes:
def normcase(path):
import ctypes
GetShortPathName = ctypes.windll.kernel32.GetShortPathNameA
GetLongPathName = ctypes.windll.kernel32.GetLongPathNameA
# First convert path to a short path
short_length = GetShortPathName(path, None, 0)
if short_length == 0:
return path
short_buf = ctypes.create_string_buffer(short_length)
GetShortPathName(path, short_buf, short_length)
# Next convert the short path back to a long path
long_length = GetLongPathName(short_buf, None, 0)
long_buf = ctypes.create_string_buffer(long_length)
GetLongPathName(short_buf, long_buf, long_length)
return long_buf.value
Using standard lib only, this one works on all path parts / subdirs (except drive letter):
def casedpath(path):
r = glob.glob(re.sub(r'([^:/\\])(?=[/\\]|$)', r'[\1]', path))
return r and r[0] or path
And this one handles UNC paths in addition:
def casedpath_unc(path):
unc, p = os.path.splitunc(path)
r = glob.glob(unc + re.sub(r'([^:/\\])(?=[/\\]|$)', r'[\1]', p))
return r and r[0] or path
Dirty hack approach,
import glob
...
if os.path.exists(d):
d_real = glob.glob(d + '*')[0][:len(d)]
Definitely ugly, but fun:
def getRealDirPath(path):
try:
open(path)
except IOError, e:
return str(e).split("'")[-2]
Of course:
- works only with dirs
- will be buggy if dir cannot be open for another reason
But can still be useful if you don't need it for "life or death" kind of code.
Tried to grep the standard lib to find how they found the real path but couldn't find it. Must be in C.
That was the dirty hack of the day, next time we will use a regexp on the stacktrace just because we can :-)
精彩评论