Windows上os.path.normcase的反向操作

6 投票
5 回答
2650 浏览
提问于 2025-04-15 16:41

有没有简单的方法可以从全小写的路径获取“真实”的区分大小写的路径?就像是os.path.normcase的反向操作。

比如,考虑这个目录:

c:\StackOverFlow

如果我有以下这段代码,怎么才能得到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

5 个回答

1

仅使用标准库,这段代码可以在所有路径部分和子目录上工作(除了驱动器字母):

def casedpath(path):
    r = glob.glob(re.sub(r'([^:/\\])(?=[/\\]|$)', r'[\1]', path))
    return r and r[0] or path

而这段代码还可以处理UNC路径,也就是网络路径:

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
1

你可以通过把 GetShortPathNameGetLongPathName 这两个函数连在一起使用来实现这个功能。理论上来说,这种方法可能会失效,因为在Windows系统中,你可以通过一些设置来关闭短文件名的功能。下面是一个使用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
1

我觉得这个解决方案并不算简单,但你可以这样做:

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)

这个方法可能效率不高(这取决于目录里有多少个文件)。它需要对路径中的各个部分进行调整(我的方法其实只修正了文件名的大小写,而不管目录名)。另外,可能可以使用 os.walk 来帮助你遍历整个目录树。

撰写回答