Python在Windows上的长路径问题

32

在Windows下编写Python程序时,我遇到了一个问题。我需要处理长于256个字符或其他限制的文件路径。

现在,我已经了解了大约两种解决方案:

  1. 使用kernel32.dll中的GetShortPathName并以这种方式访问文件。

这很好,但我无法使用它,因为我需要以某种方式使用这些路径。

shutil.rmtree(short_path)

其中short_path是一个非常短的路径(类似于D:\tools\Eclipse),而长路径出现在目录本身中(该死的Eclipse插件)。

  1. 在路径前面加上"\\\\?\\"

我尝试了各种方式都没能让它起作用。以这种方式尝试进行任何操作始终会导致错误WindowsError: [Error 123] The filename, directory name, or volume label syntax is incorrect: <path here>

所以我的问题是:如何使第二个选项起作用?我强调需要像在选项#1的示例中那样使用它。

或者

还有其他方法吗?

编辑:我需要在Python 2.7中使用解决方案

编辑2:问题Python长文件名支持在Windows中失效确实提供了带有“魔术前缀”的答案,并且我在此问题中说明我知道它。我不知道的事情是如何使用它。我尝试在路径前面添加它,但它失败了,就像我上面写的那样。


可能是Python长文件名在Windows中支持不完整的重复问题。它有一个不同的字符串要添加。您尝试使用过那个字符串吗? - AncientSwordRage
2
所以你尝试过 "\\?\\" 而不仅仅是 "\\\\?\\" 吗? - AncientSwordRage
@Pureferret:第一点:是的,我看到了,但那不是我需要的。如果我得到了长路径,我还是停留在原地。这个路径对于Python来说太长了,无法处理。 第二点:什么?:D 我正在将\?\添加到字符串前缀中,我在问题中写的只是转义字符。 - Jiří Kantor
是的,我现在意识到,在反引号中获取正确的字符很困难。问题在于路径对于Windows来说太长了,但Python并没有问题。在第二个链接中,他们将其分配给一个变量,然后运行它。你按照那个问题中的确切示例操作了吗? - AncientSwordRage
2
一个重要的技巧:如果你使用 Python 2.x,那么你的长文件名必须是 unicode 类型而不是 str 类型,因此前缀必须写成这样:u'\\\\?\\UNC\\' - herve-guerin
显示剩余3条评论
6个回答

19

看来像往常一样,在认真问别人之后的二十分钟内,我找到了解决一个困扰我一周的问题的答案。

所以我发现需要确保以下两件事情正确:

  1. 路径只能包含反斜杠(\),不能有正斜杠(/)。
  2. 如果我想要列出一个目录的内容,我需要在路径末尾加上一个反斜杠(\),否则Python会将 /*.* 添加到路径中,这是一个正斜杠(/),会造成问题。

希望至少有人会发现这个有用。


2
@Pureferret Lol :D 谢谢您的文化丰富,我以前从未听说过橡皮鸭调试。 - Jiří Kantor
2
鉴于上述问题2,似乎您没有使用unicode路径,即u'\\'.join([ur'\\?', path.decode('mbcs')])。Python会将\*.*附加到unicode路径和/*.*附加到字节字符串路径。通过添加尾随的\,它只附加了*.*,但仍然调用了ANSI API FindFirstFileA,限制为MAX_PATH个字符。 - Eryk Sun
4
如果您不熟悉Python 2.x,那么需要注意字符串字面值默认为str类型(即字节字符串),除非在前面加上u来创建一个unicode实例。如果将strunicode连接起来,则使用默认的ASCII编码解码str实例。因此,如果short_pathunicode类型,则在其前面加上'\\\\?\\'将得到一个unicode类型结果;否则,将创建一个新的str类型结果。原帖作者应该在'\\\\?\\'前加上u,即写成 u'\\\\?\\'。另外,请阅读parsing arguments and building values以了解在posix_listdir中的PyArg_ParseTuple调用发生了什么。 - Eryk Sun
@eryksun:您确定OP正在使用posix_listdir吗?他描述的行为无法通过您所描述的实现来解释。 - Harry Johnston
3
只是想分享我的经验,我和 OP 遇到了同样的问题。尽管在路径后面加了反斜线没有帮助,但将其转换为 Unicode 类型字符串确实有效。 - Ben Aaronson
显示剩余5条评论

14

如果您正在寻找直接的答案,让我简化一下:

  1. 对于Python < 3:路径必须是Unicode格式,在字符串前面加上u,例如u'C:\\path\\to\\file'
  2. 路径需要以\\\\?\\开头(转义为\\?\),例如u'\\\\?\\C:\\path\\to\\file'
  3. 不能使用正斜杠,只能使用反斜杠:/ --> \\
  4. 它必须是绝对路径;相对路径无法工作。

2
注意:项目#1是针对Python 2的,该版本在您编写此答案时已不再受支持。在Python 3中,它只需要是“str”(不需要特殊前缀来使“str”文字)。 - ShadowRanger

3

py 3.8.2

# Fix long path access:
import ntpath
ntpath.realpath = ntpath.abspath
# Fix long path access.

在我的情况下,这解决了从长路径运行脚本的问题。 (https://developers.google.com/drive/api/v3/quickstart/python) 但这不是一个通用的修复方法。 看起来ntpath.realpath实现存在问题。这段代码用一个虚拟替换了它。

9
尽管这段代码可能解决了问题,但最好还是解释一下你的代码是如何解决这个问题的。这样,未来的访问者就可以从你的帖子中学习,并将其应用于他们自己的代码中。SO不是码农服务网站,而是一个知识资源平台。此外,高质量、完整的答案更有可能被赞同。这些特点,以及要求所有帖子都是自包含的,是SO作为一个平台的一些优势,与论坛有所不同。您可以编辑以添加信息和/或引用和链接到源文件的文档来补充您的解释。 - SherylHohman

2

对我有效

import os
str1=r"C:\Users\manual\demodfadsfljdskfjslkdsjfklaj\inner-2djfklsdfjsdklfj\inner3fadsfksdfjdklsfjksdgjl\inner4dfhasdjfhsdjfskfklsjdkjfleioreirueewdsfksdmv\anotherInnerfolder4aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\5qbbbbbbbbbbbccccccccccccccccccccccccsssssssssssssssss\tmp.txt"
print(len(str1)) #346

path = os.path.abspath(str1)

if path.startswith(u"\\\\"):
    path=u"\\\\?\\UNC\\"+path[2:]
else:
    path=u"\\\\?\\"+path

with open(path,"r+") as f:
    print(f.readline())

如果在Windows中遇到了路径过长(超过258个字符)的问题,请尝试以下方法。

0
只需按照我的步骤,就可以启用长路径。
1. 打开开始菜单,搜索"注册表编辑器"。
2. 以管理员身份运行,并点击"是"。
3. 导出备份。点击左上角的文件选项,选择导出注册表数据的备份文件(完成)。
4. 展开"HKEY_LOCAL_MACHINE"文件夹。
5. 展开"System"文件夹。
6. 展开"CurrentControlSet"文件夹。
7. 展开"Control"文件夹。
8. 展开"FileSystem"文件夹。
9. 在"FileSystem"文件夹中,您会看到一个文件列表。
10. 找到"LongPathEnabled"文件,双击打开。
11. 将"数值数据"从0改为1,然后点击确定。
现在,您的长路径已启用。恭喜!

0
这个帮助我系统地实施了Viktor Tóth的答案。
str1 = '../test/test/test/test/test/tesassat/test/test/test/test/test/test/test/test/test/test/test/test/test/test/test/test/test/test/test/test/test/test/test/test/test\test_dataset.txt' #Relative path for testing
str1_unicode = str1.encode('unicode_escape').decode() # Step 1: Unicode
file_path = os.path.abspath(os.path.normpath(str1_unicode )) #Step 3 and 4: no forward slashes and absolute path
with open(file_path, "w") as f:
    print( "Just testing!")

这并没有回答问题。一旦您拥有足够的声望,您将能够评论任何帖子;相反,提供不需要提问者澄清的答案。- 来自审查 - undefined

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