在使用Python的Windows上找不到长名称的文件

在使用Python的Windows上找不到长名称的文件,python,windows,filepath,Python,Windows,Filepath,我需要在Windows中浏览具有长文件名的文件夹 我尝试使用os.listdir(),但它会因路径名过长而崩溃,这很糟糕 我尝试使用os.walk(),但它忽略了长度超过~256的路径名,这更糟糕 我尝试了所描述的神奇的解决方法,但它只适用于映射驱动器,而不适用于 下面是一个具有短路径名的示例,它表明UNC路径名不适用于“魔术”这个词 >>> os.listdir('c:\\drivers') ['nusb3hub.cat', 'nusb3hub.inf', 'nusb3hub

我需要在Windows中浏览具有长文件名的文件夹

我尝试使用
os.listdir()
,但它会因路径名过长而崩溃,这很糟糕

我尝试使用
os.walk()
,但它忽略了长度超过~256的路径名,这更糟糕

我尝试了所描述的神奇的解决方法,但它只适用于映射驱动器,而不适用于

下面是一个具有短路径名的示例,它表明UNC路径名不适用于“魔术”这个词

>>> os.listdir('c:\\drivers')
['nusb3hub.cat', 'nusb3hub.inf', 'nusb3hub.sys', 'nusb3xhc.cat', 'nusb3xhc.inf', 'nusb3xhc.sys']
>>> os.listdir('\\\\Uni-hq-srv6\\router')
['2009-04-0210', '2010-11-0909', ... ]

>>> mw=u'\\\\?\\'
>>> os.listdir(mw+'c:\\drivers')
[u'nusb3hub.cat', u'nusb3hub.inf', u'nusb3hub.sys', u'nusb3xhc.cat', u'nusb3xhc.inf', u'nusb3xhc.sys']
>>> os.listdir(mw+'\\\\Uni-hq-srv6\\router')

Traceback (most recent call last):
  File "<pyshell#160>", line 1, in <module>
    os.listdir(mw+'\\\\Uni-hq-srv6\\router')
WindowsError: [Error 123] The filename, directory name, or volume label syntax is incorrect: u'\\\\?\\\\\\Uni-hq-srv6\\router\\*.*'
结果如下:

  • 数字8表示找到了所有文件
  • 数字0表示它甚至没有尝试而不崩溃
  • 任何介于1和7之间的数字都意味着它在中途失败而没有崩溃
  • 单词
    Crash
    表示它崩溃了
-


使用8.3回退以避免长路径名,在Win7资源管理器中浏览这似乎是windows本身所做的,即每个长路径都有一个较短的“真实名称”:

>>> long_unc="\\\\K53\\Users\\Tolan\\testing\\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\\xxxxxxxxxxxxxxxxxxxxxxxxdddddddddddddddddddddwgggggggggggggggggggggggggggggggggggxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\\esssssssssssssssssssssggggggggggggggggggggggggggggggggggggggggggggggeee"
>>> os.listdir(long_unc)
FileNotFoundError: [WinError 3]
但您可以使用Win32 API(pywin32)来“构建”较短的版本,即

short_unc=win32api.GetShortPathName(win32api.GetShortPathName(win32api.GetShortPathName("\\\\K53\\Users\\Tolan\\testing\\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")+"\\xxxxxxxxxxxxxxxxxxxxxxxxdddddddddddddddddddddwgggggggggggggggggggggggggggggggggggxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx") + "\\esssssssssssssssssssssggggggggggggggggggggggggggggggggggggggggggggggeee")
>>> print(short_unc)
\\K53\Users\Tolan\testing\XXXXXX~1\XXXXXX~1\ESSSSS~1
>>> import os
>>> os.listdir(short_unc)
['test.txt']
显然,您可以将win32api.GetShortPathName调用折叠到dir探索中,而不是像我的示例中那样嵌套。
我这样做是因为如果你已经有了一个“太长”的路径,那么win32api.GetShortPathName也不会处理它,但是你可以按目录执行,并保持在限制之下。

要在UNC路径上定位文件,神奇的前缀是
\?\UNC\
,而不仅仅是
\?\

参考:

所以要访问
//server/share/really/deep/path/etc/etc
,您需要

  • 将其转换为unicode(使用
    unicode()
    构造函数)
  • 添加魔法前缀(
    “\\?\\UNC\”
    ),然后
  • 确保所有目录分隔符都是
    “\”
    (请参阅
    os.path.normpath()
  • 生成的unicode字符串:
    \\?\UNC\server\share\really\deep\path\etc\etc

    我只做了一点实验(比@stenci少得多),但在Python2.7中,它似乎在
    os.walk()
    中正常工作,而在
    os.listdir()中失败


    警告:如果遍历的起始路径在MAX_path限制内,并且起始路径中的任何子目录都不会将其推过该限制,则它仅适用于os.walk()。这是因为as os.walk()在顶部目录中使用os.listdir()。

    在我之前的评论中,我说过不需要嵌套递归调用
    GetShortPathName
    。我发现大多数时候都不需要它,但偶尔它会崩溃。我不知道是什么时候,所以我做了一个小函数,这个函数已经平稳运行了一段时间:

    这是我现在使用的函数:

    def short_name(name):
        try:
            return win32api.GetShortPathName(name)
        except win32api.error:
            dirname = os.path.dirname(name)
            basename = os.path.basename(name)
            short_dirname = win32api.GetShortPathName(dirname)
            return win32api.GetShortPathName(os.path.join(short_dirname, basename))
    
    try:
        mtime = os.path.getmtime(name)
    except FileNotFoundError:
        name = short_name(name)
        mtime = os.path.getmtime(name)
    

    使用
    net use
    并为UNC分配驱动器号如何?@iTayb:谢谢。这很难看,但应该有用。我需要扫描几个网络驱动器,所以我应该
    net-use
    它们,然后
    net-use/delete
    它们。我想知道这是在py2还是py3上,如果是py2,py3上的行为是否不同?我很久没有使用Windows了,只是好奇:会
    glob.glob(“*”)
    为您工作?这是一个很好的问题。你能不能让标题更具描述性,这样人们在将来搜索时就更有可能找到它?类似于“在使用Python的Windows上找不到长名称的文件”的情况,看起来不需要嵌套调用。调用
    win32api.GetShortPathName('C:\\test\\123456789 123456789 123456789 123456789 123456789\\123456789 123456789 123456789')
    返回
    C:\test\123456~1\123456~1
    。调用
    short\u name(dirname)
    而不是
    GetShortPahtName(dirname)
    会是一个很好的改进吗?它会将路径分解到所需的最小值,然后添加所有剩余的位……一个重要的技巧是:如果使用Python 2.x:
    u'\\\\?\\UNC\\\'
    short_unc=win32api.GetShortPathName(win32api.GetShortPathName(win32api.GetShortPathName("\\\\K53\\Users\\Tolan\\testing\\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")+"\\xxxxxxxxxxxxxxxxxxxxxxxxdddddddddddddddddddddwgggggggggggggggggggggggggggggggggggxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx") + "\\esssssssssssssssssssssggggggggggggggggggggggggggggggggggggggggggggggeee")
    >>> print(short_unc)
    \\K53\Users\Tolan\testing\XXXXXX~1\XXXXXX~1\ESSSSS~1
    >>> import os
    >>> os.listdir(short_unc)
    ['test.txt']
    
    def short_name(name):
        try:
            return win32api.GetShortPathName(name)
        except win32api.error:
            dirname = os.path.dirname(name)
            basename = os.path.basename(name)
            short_dirname = win32api.GetShortPathName(dirname)
            return win32api.GetShortPathName(os.path.join(short_dirname, basename))
    
    try:
        mtime = os.path.getmtime(name)
    except FileNotFoundError:
        name = short_name(name)
        mtime = os.path.getmtime(name)