Python创建长文件时出现IOError异常

10
使用"open(fname,'w+')"打开新文件时,出现以下IOError。完整的错误消息如下:
文件不存在,但是使用 "os.access(dir_name, os.W_OK)" 和 "os.path.exists (dir_name)" 验证其父目录确实存在。
我在想,也许文件名对于Windows来说太长了,或者我做错了什么。如果有任何提示,将不胜感激。非常感谢。
错误消息:
IOError:[Errno 2] 没有这样的文件或目录:'C:\ Documents and Settings \ Administrator \ op_models \ Corp_Network_Nov12 \ abcde_corporate_nov_12.project \ abcde_corporate_nov_12-ctr.rptd.dir \ ctr \ Non Business Hours for Weeknights \ hourly_data_for_2_weeks \ 1294897740 \ json.data \ Link \ 0 \ Link Utilization \ analyzer393146160-data0.js'

谢谢。字符数限制确实超过了260个。MSDN文章提到我们可以使用“\?\”前缀来处理长文件名,只是好奇有没有人知道如何将前缀添加到文件名中。当我尝试进行简单的“+”操作时,会出现错误“EOL while scanning single-quoted string'”。(fname='\?' + fname) - AshD
请使用 "\\?\"。在这种情况下,原始字符串将无法工作。 - cgohlke
请使用正斜杠代替反斜杠。另请参阅http://stackoverflow.com/faq#howtoask。 - johnsyweb
我尝试在文件名后面添加“\\?\"和“\\UNC\?\",但仍然出现了相同的异常。无论如何,当我尝试在Windows资源管理器中创建文件时,它都不允许我创建文件(Windows会阻止我添加字符)。我猜这是系统限制? - AshD
5个回答

7

1
结合非常令人困惑的错误值;它应该是ENAMETOOLONG,而不是ENOENT。我认为这是那些晦涩的Windows漏洞之一,每个人在职业生涯中都会至少被困惑一次。 - Glenn Maynard
非英语语言怎么样?我感觉最高限制更低。 - Vitaly Zdanevich

5

以下是适用于我个人的相关代码(我有非常长的文件名和路径):

for d in os.walk(os.getcwd()):
    dirname = d[0]
    files = d[2]
    for f in files:
        long_fname = u"\\\\?\\" + os.getcwd() + u"\\" + dirname + u"\\" + f
        if op.isdir(long_fname):
            continue
        fin = open(long_fname, 'rb')
        ...

请注意,对于我而言,只有以下所有组合才有效:
  1. 在前面添加'\\?\'。

  2. 使用完整路径,而不是相对路径。

  3. 只使用反斜杠。

  4. 在Python中,文件名字符串必须是unicode字符串,例如u"abc",而不是"abc"。

此外,请注意,由于某种原因,os.walk(..)返回一些目录作为文件,因此我检查了这一点。

非常感谢提醒Python字符串必须是Unicode字符串-这拯救了我! - Frerich Raabe
os.getcwd() 对我来说解决了问题。必须是完整路径,不能只是相对路径。 - Blairg23

4
你可以使用以下方法来进行 tarfile 模块的猴子补丁操作:

import tarfile

def monkey_patch_tarfile():
    import os
    import sys
    if sys.platform not in ['cygwin', 'win32']:
        return
    def long_open(name, *args, **kwargs):
    # http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx#maxpath
        if len(name) >= 200:
            if not os.path.isabs(name):
                name = os.path.join(os.getcwd(), name)
            name = "\\\\?\\" + os.path.normpath(name)
        return long_open.bltn_open(name, *args, **kwargs)
    long_open.bltn_open = tarfile.bltn_open
    tarfile.bltn_open = long_open

monkey_patch_tarfile()

0

如果不是文件名的长度,就是文件名的内容...

Python将'\12'视为控制序列。

>>> fn='C:\Documents and Settings\Administrator\op_models\Corp_Network_Nov12\abcde_corporate_nov_12.project\abcde_corporate_nov_12-ctr.rptd.dir\ctr\Non Business Hours for Weeknights\hourly_data_for_2_weeks\1294897740\json.data\Link\0\Link Utilization\analyzer393146160-data0.js'
>>> print fn
C:\Documents and Settings\Administrator\op_models\Corp_Network_Nov12bcde_corporate_nov_12.projectbcde_corporate_nov_12-ctr.rptd.dir\ctr\Non Business Hours for Weeknights\hourly_data_for_2_weeks
94897740\json.data\Link\Link Utilizationnalyzer393146160-data0.js

使用原始字符串来处理Windows文件名会很有帮助:

>>> fn=r'C:\Documents and Settings\Administrator\op_models\Corp_Network_Nov12\abcde_corporate_nov_12.project\abcde_corporate_nov_12-ctr.rptd.dir\ctr\Non Business Hours for Weeknights\hourly_data_for_2_weeks\1294897740\json.data\Link\0\Link Utilization\analyzer393146160-data0.js'
>>> print fn
C:\Documents and Settings\Administrator\op_models\Corp_Network_Nov12\abcde_corporate_nov_12.project\abcde_corporate_nov_12-ctr.rptd.dir\ctr\Non Business Hours for Weeknights\hourly_data_for_2_weeks\1294897740\json.data\Link\0\Link Utilization\analyzer393146160-data0.js

更新

或者,使用正斜杠“/”代替反斜杠“\”,因为这将在所有操作系统上工作,并且将为您节省在路径名末尾的反斜杠中出现问题的麻烦,就像您的注释中所述。

另请参见{{link1:os.path.join()}}。

更新2

问题的简化演示:

>>> open('.\12\n\r\file.txt')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IOError: [Errno 2] No such file or directory: '.\n\n\r\x0cile.txt'
>>> open('./12/n/r/file.txt')
<open file './12/n/r/file.txt', mode 'r' at 0x7ff83f98>

C:\Users\johnysweb>copy .\12\n\r\file.txt con
Blah
        1 file(s) copied.

2
最好始终使用正斜杠;它们在Windows中运行良好,并且会导致代码更有可能在其他平台上工作。 - Glenn Maynard
1
原帖使用了正确编码的文件路径,否则错误信息将会不同(TypeError)。 - cgohlke
@cgohlke:请查看我的第二次更新,其中演示了与OP报告的相同文本的“IOError”异常。 - johnsyweb
我认为编码是正确的,因为我刚试了一个不同的文件名(带有完整路径的sm.txt),这使我保持在260个字符的限制内,而且没有出现异常。我确实看到文件被创建了。 - AshD
2
@Johnsyweb:我不怀疑使用错误编码的路径名会导致IOError。然而,OP使用的路径名包含一个NULL字节“\ 0”,这将导致open函数中出现TypeError。 OP手动输入260+个字符的路径名的可能性也很小。更有可能是函数调用的结果。 - cgohlke

0

检查整个路径的长度,然后附加必要的Windows长路径格式。需要注意的是,这不适用于从远程目录访问数据,即以'\\some_remote_location\..'开头的路径,因此您需要在本地映射该目录才能使“长路径”正常工作。

if len(path_and_file) > 250: #I think the max is 260 but I left a buffer :)
    path_and_file = '\\\\?\\'+path_and_file

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