使用Python在Windows上无法找到长名称的文件 [英] Unable to locate files with long names on Windows with Python
问题描述
我需要在Windows中浏览具有长文件名的文件夹.
I need to walk through folders with long file names in Windows.
我尝试使用os.listdir()
,但是使用长路径名会崩溃,这很糟糕.
I tried using os.listdir()
, but it crashes with long pathnames, which is bad.
我尝试使用os.walk()
,但是它忽略的路径名长于〜256,这更糟.
I tried using os.walk()
, but it ignores the pathnames longer than ~256, which is worse.
我尝试了此处中描述的魔术字变通方法,但它仅适用于映射驱动器,不适用于UNC路径名.
I tried the magic word workaround described here, but it only works with mapped drives, not with UNC pathnames.
这里是一个带有短路径名的示例,它表明UNC路径名不适用于魔术词技巧.
Here is an example with short pathnames, that shows that UNC pathnames don't work with the magic word trick.
>>> 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\\*.*'
关于如何处理长路径名或Unicode UNC路径名的任何想法?
Any idea on how to deal with long pathnames or with unicode UNC pathnames?
根据以下注释的建议,我创建了一些测试函数以比较Python 2.7和3.3,并在os.chdir
之后添加了glob.glob
和os.listdir
的测试.
Following the suggestion of the comments below, I created some test functions to compare Python 2.7 and 3.3, and I added the test of glob.glob
and os.listdir
after os.chdir
.
os.chdir
未能按预期提供帮助(请参阅此评论).
The os.chdir
didn't help as expected (see this comment).
glob.glob
是唯一在Python 3.3中工作得更好的,但仅在一种情况下:使用魔术字并使用驱动器名称.
The glob.glob
is the only one that in Python 3.3 works better, but only in one condition: using the magic word and with the drive name.
这是我使用的代码(适用于2.7和3.3).我现在正在学习Python,希望这些测试有意义:
Here is the code I used (it works on both 2.7 and 3.3). I am learning Python now, and I hope these tests make sense:
from __future__ import print_function
import os, glob
mw = u'\\\\?\\'
def walk(root):
n = 0
for root, dirs, files in os.walk(root):
n += len(files)
return n
def walk_mw(root):
n = 0
for root, dirs, files in os.walk(mw + root):
n += len(files)
return n
def listdir(root):
try:
folders = [f for f in os.listdir(root) if os.path.isdir(os.path.join(root, f))]
files = [f for f in os.listdir(root) if os.path.isfile(os.path.join(root, f))]
n = len(files)
for f in folders:
n += listdir(os.path.join(root, f))
return n
except:
return 'Crash'
def listdir_mw(root):
if not root.startswith(mw):
root = mw + root
try:
folders = [f for f in os.listdir(root) if os.path.isdir(os.path.join(root, f))]
files = [f for f in os.listdir(root) if os.path.isfile(os.path.join(root, f))]
n = len(files)
for f in folders:
n += listdir_mw(os.path.join(root, f))
return n
except:
return 'Crash'
def listdir_cd(root):
try:
os.chdir(root)
folders = [f for f in os.listdir('.') if os.path.isdir(os.path.join(f))]
files = [f for f in os.listdir('.') if os.path.isfile(os.path.join(f))]
n = len(files)
for f in folders:
n += listdir_cd(f)
return n
except:
return 'Crash'
def listdir_mw_cd(root):
if not root.startswith(mw):
root = mw + root
try:
os.chdir(root)
folders = [f for f in os.listdir('.') if os.path.isdir(os.path.join(f))]
files = [f for f in os.listdir('.') if os.path.isfile(os.path.join(f))]
n = len(files)
for f in folders:
n += listdir_cd(f) # the magic word can only be added the first time
return n
except:
return 'Crash'
def glb(root):
folders = [f for f in glob.glob(root + '\\*') if os.path.isdir(os.path.join(root, f))]
files = [f for f in glob.glob(root + '\\*') if os.path.isfile(os.path.join(root, f))]
n = len(files)
for f in folders:
n += glb(os.path.join(root, f))
return n
def glb_mw(root):
if not root.startswith(mw):
root = mw + root
folders = [f for f in glob.glob(root + '\\*') if os.path.isdir(os.path.join(root, f))]
files = [f for f in glob.glob(root + '\\*') if os.path.isfile(os.path.join(root, f))]
n = len(files)
for f in folders:
n += glb_mw(os.path.join(root, f))
return n
def test():
for txt1, root in [('drive ', r'C:\test'),
('UNC ', r'\\Uni-hq-srv6\router\test')]:
for txt2, func in [('walk ', walk),
('walk magic word ', walk_mw),
('listdir ', listdir),
('listdir magic word ', listdir_mw),
('listdir cd ', listdir_cd),
('listdir magic word cd ', listdir_mw_cd),
('glob ', glb),
('glob magic word ', glb_mw)]:
print(txt1, txt2, func(root))
test()
结果如下:
- 数字8表示找到了所有文件
- 数字0表示它甚至没有尝试都不会崩溃
- 介于1到7之间的任何数字表示失败了一半而没有崩溃
-
Crash
一词表示它已崩溃
- The number 8 means all the files were found
- The number 0 means it didn't even try without crashing
- Any number between 1 and 7 means it failed half way without crashing
- The word
Crash
means it crashed
-
Python 2.7
drive walk 5
drive walk magic word 8 * GOOD *
drive listdir Crash
drive listdir magic word 8 * GOOD *
drive listdir cd Crash
drive listdir magic word cd 5
drive glob 5
drive glob magic word 0
UNC walk 6
UNC walk magic word 0
UNC listdir 5
UNC listdir magic word Crash
UNC listdir cd 5
UNC listdir magic word cd Crash
UNC glob 5
UNC glob magic word 0
Python 3.3
drive walk 5
drive walk magic word 8 * GOOD *
drive listdir Crash
drive listdir magic word 8 * GOOD *
drive listdir cd Crash
drive listdir magic word cd 5
drive glob 5
drive glob magic word 8 * GOOD *
UNC walk 6
UNC walk magic word 0
UNC listdir 5
UNC listdir magic word Crash
UNC listdir cd 5
UNC listdir magic word cd Crash
UNC glob 5
UNC glob magic word 0
推荐答案
使用8.3后备以避免长路径名,在Win7资源管理器中浏览,这似乎是Windows本身所做的,即每个长路径都有一个较短的'true name ':
Use the 8.3 fallback to avoid the long pathname, browsing in Win7 explorer this seems to be what windows itself does, ie every long paths has a shorter 'true name':
>>> long_unc="\\\\K53\\Users\\Tolan\\testing\\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\\xxxxxxxxxxxxxxxxxxxxxxxxdddddddddddddddddddddwgggggggggggggggggggggggggggggggggggxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\\esssssssssssssssssssssggggggggggggggggggggggggggggggggggggggggggggggeee"
>>> os.listdir(long_unc)
FileNotFoundError: [WinError 3]
但是您可以使用win32api(pywin32)构建"较短的版本,即
but you can use win32api (pywin32) to 'build' up a shorter version, ie
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调用折叠到目录探索中,而不是像我的示例中那样嵌套. 我已经通过3次调用完成了此操作,因为如果您已经拥有太长"的路径,则win32api.GetShortPathName也无法解决该问题,但是您可以按目录进行操作并保持在限制以下.
clearly you can just fold the win32api.GetShortPathName call into you dir exploration rather than nesting as in my example. I've done it like this with 3 calls because if you've already got a 'too long' path then win32api.GetShortPathName wont cope with it either, but you can do it per dir and stay below the limit.
这篇关于使用Python在Windows上无法找到长名称的文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!