Windowsで長いファイル名のフォルダーをウォークスルーする必要があります。
os.listdir()
を使用しようとしましたが、長いパス名でクラッシュします。これは悪いことです。
os.walk()
を使用してみましたが、〜256より長いパス名は無視されます。これはさらに悪いことです。
ここ で説明されている魔法のWordの回避策を試しましたが、マップされたドライブでのみ機能し、 NCパス名 では機能しません。
これは短いパス名の例で、UNCパス名が魔法のWordトリックでは機能しないことを示しています。
>>> 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\\*.*'
長いパス名またはユニコードUNCパス名を処理する方法についてのアイデアはありますか?
編集:
以下のコメントの提案に従って、Python 2.7と3.3を比較するためのいくつかのテスト関数を作成し、glob.glob
の後にos.listdir
とos.chdir
のテストを追加しました。
os.chdir
は期待どおりに機能しませんでした(これを参照 コメント )。
glob.glob
は、Python 3.3でより適切に機能する唯一のものですが、1つの条件でのみ、魔法の言葉を使用し、ドライブ名を使用します。
これが私が使用したコードです(2.7と3.3の両方で動作します)。私は今Pythonを学んでいます、そしてこれらのテストが理にかなっていることを願っています:
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()
そしてここに結果があります:
Crash
は、クラッシュしたことを意味します-
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フォールバックを使用して、長いパス名を回避します。Win7Explorerで参照すると、これはWindows自体が行うことのようです。つまり、すべての長いパスには短い「実際の名前」があります。
>>> long_unc="\\\\K53\\Users\\Tolan\\testing\\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\\xxxxxxxxxxxxxxxxxxxxxxxxdddddddddddddddddddddwgggggggggggggggggggggggggggggggggggxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\\esssssssssssssssssssssggggggggggggggggggggggggggggggggggggggggggggggeee"
>>> os.listdir(long_unc)
FileNotFoundError: [WinError 3]
ただし、win32api(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呼び出しをdirexplorationに折りたたむことができます。すでに「長すぎる」パスがある場合はwin32api.GetShortPathNameも対応できないため、3回の呼び出しでこのように実行しましたが、ディレクトリごとに実行して制限を下回ることができます。
UNCパス上のファイルを見つけるための魔法のプレフィックスは、単なる_\\?\UNC\
_ではなく_\\?\
_です。
参照: https://msdn.Microsoft.com/en-us/library/aa365247(VS.85).aspx#maxpath
したがって、_//server/share/really/deep/path/etc/etc
_にアクセスするには、次のことを行う必要があります。
unicode()
コンストラクターを使用します)"\\?\\UNC\"
_)を追加し、"\"
_であることを確認します(os.path.normpath()
を参照)結果のUnicode文字列:_\\?\UNC\server\share\really\deep\path\etc\etc
_
私は少しだけ実験しましたが(@stenciよりもはるかに少ないです)、Python 2.7では、os.walk()
で問題なく動作し、os.listdir()
。
警告:トラバーサルの開始パスがMAX_PATH制限内にあり、開始パス内のどのサブディレクトリも制限を超えない場合にのみ、os.walk()で機能します。 。これは、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)