Python Windows上os.path.normcase的反转

Python Windows上os.path.normcase的反转,python,path,filenames,case-sensitive,Python,Path,Filenames,Case Sensitive,是否有一种简单的方法可以从全小写路径中获取“真实”区分大小写的路径。 与os.path.normcase相反 例如,考虑目录: c:\StackOverFlow 如果我有以下代码片段,如何获得d_real >>> import os >>> d = os.path.normcase('C:\\StackOverFlow') # convert to lower case >>> d 'c:\\stackoverflow' >>&

是否有一种简单的方法可以从全小写路径中获取“真实”区分大小写的路径。 与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
肮脏的黑客手段

import glob
...
if os.path.exists(d):
    d_real = glob.glob(d + '*')[0][:len(d)]

我不认为这个解决方案简单,但你能做的是:

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
有助于沿树向下移动。

确实很难看,但很有趣:

def getRealDirPath(path):
    try:
        open(path)
    except IOError, e:
        return str(e).split("'")[-2]
当然:

  • 仅适用于dir
  • 如果目录因其他原因无法打开,则会出现错误
但如果您不需要它来编写“生死”之类的代码,它仍然很有用

试图对标准库进行grep,以找到他们是如何找到真实路径的,但找不到。必须是C


这是今天最糟糕的黑客行为,下次我们将在stacktrace上使用regexp,因为我们可以:-)

您可以通过链接
GetShortPathName
GetLongPathName
来实现这一点。这在理论上是行不通的,因为您可以通过某些配置设置在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

仅使用标准库,此库适用于所有路径零件/子曲面(驱动器号除外):

这一个还处理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

os.path.join('c:','stackoverflow')
提供的是
c:stackoverflow
,而不是
c:\stackoverflow
,如文档中所述(=相对于指定驱动器上当前目录的路径)。是的,我没有检查示例代码。我会修好的。谢谢。glob.glob(d+“*”)在Windows上返回一个空列表(至少对我来说是这样)@jhwist,我在Windows上测试了它,它运行正常。你用了什么来做
d
?嗯,可能是cygwin风格的路径,我的
d=“c:/existing_file”
这非常有效,只是路径的驱动器或网络组件仍然可以是任意情况。我发现添加
parts=os.path.splitdrive(os.path.normcase(path))
path=parts[0].upper()+parts[1]很有用
添加到函数的开头,这样我就可以使用大写驱动器号和小写网络路径。注意:对于此文件系统相关解决方案,首先检查是否在Windows卷上关闭了短文件名生成(
fsutil.exe 8dot3name query C:
)-同时,为了提高性能,建议使用此选项,除非16位应用程序仍在大吃大喝。@Alecz,文件是主要用例。无法重现该问题。例子?已知:它没有大写可能的驱动器号(和UNC服务名称);不转换斜杠->反斜杠。它不会对现在不存在的文件/目录执行任何操作(仅存在部分路径)。或者您使用的测试路径带有false/missing反斜杠转义或缺少原始字符串前缀r-例如,
“some\\false\rawpath.txt”
。我也无法再重现此结果。它工作得很好,我认为这是一个非常巧妙的解决方案。我将删除我的其他评论。谢谢
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