Python:如何获取在Windows中存储的文件名大小写?

16
尽管 Windows 不区分大小写,但它确实会保留文件名的大小写。在 Python 中,有没有办法获得与文件系统中存储的大小写相同的文件名?
例如,在 Python 程序中,我有一个文件名为“texas.txt”,但想知道它实际上是以“TEXAS.txt”形式存储在文件系统中的,即使这对于各种文件操作来说并不重要。

意外的重复账户已合并。 - Marc Gravell
6个回答

10

这是最简单的做法:

>>> import win32api
>>> win32api.GetLongPathName(win32api.GetShortPathName('texas.txt')))
'TEXAS.txt'

1
win32api.GetLongPathName(win32api.GetShortPathName('texas.txt')) 这段代码能够正常工作吗? - Sridhar Ratnakumar
2
没错,那个可行。实际上,为了澄清一下,你原本的建议是可行的,但如果包括目录,则不行,例如,win32api.GetLongPathName('\\states\\texas.txt') 会得到 '\\states\\TEXAS.txt',而 win32api.GetShortPathName('\\states\\texas.txt')) 正确地得到了 '\\STATES\\TEXAS.txt'。这让我有些困惑,现在我明白了。谢谢! - diggums
我明白了。那么,我已经修改了我的答案,也调用了 win32api.GetShortPathName - Sridhar Ratnakumar
3
伟大的解决方案;要澄清一下:令人困惑的内部GetShortPathName()调用是必需的,因为GetLongPathName()不会对已经处于长格式(非8.3格式)的路径进行大小写校正。在Python 3.x中,示例可以直接使用具有非ASCII文件名的字符串,但是在2.x中,您必须显式使用Unicode字符串并调用GetLongPathNameW()(注意W)。如果您拥有pip,则可以通过运行pip install pypiwin32来安装win32api模块(通过pypiwin32包)。 - mklement0
2
请注意,如果文件没有短文件名(如果系统或卷禁用了短文件名生成,则可能会发生这种情况),则此解决方案将*不起作用。此外,“GetLongPathName”不会更正驱动器字母的大小写。 - jamesdlin
这似乎在某些情况下失败了,请参见 https://github.com/thonny/thonny/issues/925 - Aivar

6
我在使用上面的win32api解决方案时遇到了特殊字符的问题。对于Unicode文件名,您需要使用以下内容:
win32api.GetLongPathNameW(win32api.GetShortPathName(path))

2
好的一点(适用于Python 2.x - 在本地支持Unicode的3.x上不需要)。只是为了明确:输入路径(也)必须是Unicode字符串(例如,u'texas.txt')。 - mklement0
请查看我对 https://dev59.com/BXI95IYBdhLWcg3w3iHG#2114975 的评论;如果短文件名生成被禁用,这并不保证能够正常工作。 - jamesdlin

4

这是标准库中的一个函数,只会转换路径中除驱动器盘符以外的部分:

def casedpath(path):
    r = glob.glob(re.sub(r'([^:/\\])(?=[/\\]|$)|\[', r'[\g<0>]', 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'[\g<0>]', p))
    return r and r[0] or path

注意:它比文件系统相关的Win API“GetShortPathName”方法稍慢,但可以在各个平台和文件系统中使用,即使在Windows卷上关闭了短文件名生成(fsutil.exe 8dot3name query C:)。后者至少对于性能关键的文件系统是推荐的,当没有16位应用程序再依赖于它时:

fsutil.exe behavior set disable8dot3 1

在像 copy[12] 这样的路径中,保护方括号也是必要的。如果您不介意,我将使用 glob.escape 来增强答案。 - robyschek
@robyschek 是的,不过我将保护直接嵌入到子程序中,这样它也支持结束 [(例如 oddfilename[oddfilename])和 Py 2.7 & <3.4。 - kxr

1
>>> import os
>>> os.listdir("./")
['FiLeNaMe.txt']

这个回答解决了你的问题吗?


1

你可以使用以下代码:

import os
a = os.listdir('mydirpath')
b = [f.lower() for f in a]
try:
    i = b.index('texas.txt')
    print a[i]
except ValueError:
    print('File not found in this directory')

当然,这假设你的搜索字符串'texas.txt'是小写的。如果不是,你需要先将它转换为小写。


2
print ([f for f in os.listdir("mydirpath") if f.lower() == "texas.txt"]+["file not found"])[0] - Roger Pate
@Roger:哈哈,太棒了!我还在努力掌握列表推导的威力。不过,我倾向于不用一行代码来回答问题,因为它们往往更容易让人困惑,而不是有所启发 :)。 - Chinmay Kanchi
请注意:现在不再需要使用string.lower()了。 - ghostdog74
except 块在功能上什么也不做 —— 因此会默默地忽略错误。 - Sridhar Ratnakumar
@Chinmay:仔细看看你的except块中的语句(即程序的最后一行)。它什么也没做。 - Sridhar Ratnakumar

1

如果你想要递归目录

import os
path=os.path.join("c:\\","path")
for r,d,f in os.walk(path):
    for file in f:
        if file.lower() == "texas.txt":
              print "Found: ",os.path.join( r , file )

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接