路径名太长无法打开?

Posted

技术标签:

【中文标题】路径名太长无法打开?【英文标题】:Pathname too long to open? 【发布时间】:2016-07-13 04:08:45 【问题描述】:

这是执行截图:

如您所见,错误提示“JSONFiles/Apartment/Rent/dubizzleabudhabiproperty”目录不存在。

但是请看一下我的文件:

文件夹肯定在那里。

更新 2

代码

self.file = open("JSONFiles/"+ item["category"]+"/" + item["action"]+"/"+ item['source']+"/"+fileName + '.json', 'wb') # Create a new JSON file with the name = fileName parameter
        line = json.dumps(dict(item)) # Change the item to a JSON format in one line
        self.file.write(line) # Write the item to the file

更新

当我将文件名更改为较小的文件名时,它可以工作,所以问题在于路径的长度。请问有什么解决办法?

【问题讨论】:

文件夹中有文件吗?同名? @pp_ no 文件夹为空,如果文件不存在,“w”选项会创建该文件。 使用windows时请使用os.path.join()创建路径。 文件名中可能有“特殊”字符,也可能太长。 我并不奇怪,只是猜测。 【参考方案1】:

常规 DOS 路径仅限于 MAX_PATH (260) 个字符,包括字符串的终止 NUL 字符。您可以使用以\\?\ 前缀开头的扩展长度路径来超过此限制。此路径必须是 Unicode 字符串,完全限定,并且仅使用反斜杠作为路径分隔符。根据 Microsoft 的 file system functionality comparison,最大扩展路径长度为 32760 个字符。单个文件或目录名称最多可包含 255 个字符(UDF 文件系统为 127 个字符)。 \\?\UNC\server\share 也支持扩展 UNC 路径。

例如:

import os

def winapi_path(dos_path, encoding=None):
    if (not isinstance(dos_path, unicode) and 
        encoding is not None):
        dos_path = dos_path.decode(encoding)
    path = os.path.abspath(dos_path)
    if path.startswith(u"\\\\"):
        return u"\\\\?\\UNC\\" + path[2:]
    return u"\\\\?\\" + path

path = winapi_path(os.path.join(u"JSONFiles", 
                                item["category"],
                                item["action"], 
                                item["source"], 
                                fileName + ".json"))
>>> path = winapi_path("C:\\Temp\\test.txt")
>>> print path
\\?\C:\Temp\test.txt

请参阅 MSDN 上的以下页面:

Naming Files, Paths, and Namespaces Defining an MS-DOS Device Name Kernel object namespaces

背景

Windows 调用 NT 运行时库函数RtlDosPathNameToRelativeNtPathName_U_WithStatus 将 DOS 路径转换为本机 NT 路径。如果我们open(即CreateFile)在后一个函数上设置断点的上述路径,我们可以看到它如何处理以\\?\前缀开头的路径。

Breakpoint 0 hit
ntdll!RtlDosPathNameToRelativeNtPathName_U_WithStatus:
00007ff9`d1fb5880 4883ec58        sub     rsp,58h
0:000> du @rcx
000000b4`52fc0f60  "\\?\C:\Temp\test.txt"
0:000> r rdx
rdx=000000b450f9ec18
0:000> pt
ntdll!RtlDosPathNameToRelativeNtPathName_U_WithStatus+0x66:
00007ff9`d1fb58e6 c3              ret

结果将\\?\替换为NT DOS设备前缀\??\,并将字符串复制到本机UNICODE_STRING

0:000> dS b450f9ec18
000000b4`536b7de0  "\??\C:\Temp\test.txt"

如果您使用//?/ 而不是\\?\,则路径仍限制为MAX_PATH 字符。如果太长,则RtlDosPathNameToRelativeNtPathName 返回状态码STATUS_NAME_TOO_LONG (0xC0000106)。

如果您使用 \\?\ 作为前缀但在路径的其余部分使用斜杠,Windows 不会为您将斜杠转换为反斜杠:

Breakpoint 0 hit
ntdll!RtlDosPathNameToRelativeNtPathName_U_WithStatus:
00007ff9`d1fb5880 4883ec58        sub     rsp,58h
0:000> du @rcx
0000005b`c2ffbf30  "\\?\C:/Temp/test.txt"
0:000> r rdx
rdx=0000005bc0b3f068
0:000> pt
ntdll!RtlDosPathNameToRelativeNtPathName_U_WithStatus+0x66:
00007ff9`d1fb58e6 c3              ret
0:000> dS 5bc0b3f068
0000005b`c3066d30  "\??\C:/Temp/test.txt"

正斜杠是 NT 命名空间中的有效对象名称字符。它由 Microsoft 文件系统保留,但您可以在其他命名的内核对象中使用正斜杠,这些对象存储在 \BaseNamedObjects\Sessions\[session number]\BaseNamedObjects 中。另外,我认为 I/O 管理器不会对设备和文件名中的保留字符强制执行策略。这取决于设备。也许有人在那里有一个 Windows 设备,它实现了一个名称空间,允许名称中的正斜杠。至少您可以创建包含正斜杠的 DOS 设备名称。例如:

>>> kernel32 = ctypes.WinDLL('kernel32')
>>> kernel32.DefineDosDeviceW(0, u'My/Device', u'C:\\Temp')
>>> os.path.exists(u'\\\\?\\My/Device\\test.txt')
True

您可能想知道\?? 的含义。这曾经是对象命名空间中 DOS 设备链接的实际目录,但从 NT 5(或 NT 4 w/终端服务)开始,这变成了一个虚拟前缀。对象管理器通过首先检查目录\Sessions\0\DosDevices\[LOGON_SESSION_ID] 中的登录会话的DOS 设备链接然后检查\Global?? 目录中的系统范围的DOS 设备链接来处理此前缀。

请注意,前者是登录会话,而不是 Windows 会话。登录会话目录都在 Windows 会话 0 的 DosDevices 目录下(即 Vista+ 中的服务会话)。因此,如果您有一个用于非提升登录的映射驱动器,您会发现它在提升的命令提示符中不可用,因为您的提升令牌实际上用于不同的登录会话。

DOS 设备链接的示例是\Global??\C: => \Device\HarddiskVolume2。在这种情况下,DOS C: 驱动器实际上是到HarddiskVolume2 设备的符号链接。

这里简要概述了系统如何处理解析打开文件的路径。假设我们调用 WinAPI CreateFile,它会将转换后的 NT UNICODE_STRING 存储在 OBJECT_ATTRIBUTES 结构中并调用系统函数 NtCreateFile

0:000> g
Breakpoint 1 hit
ntdll!NtCreateFile:
00007ff9`d2023d70 4c8bd1          mov     r10,rcx
0:000> !obja @r8
Obja +000000b450f9ec58 at 000000b450f9ec58:
        Name is \??\C:\Temp\test.txt
        OBJ_CASE_INSENSITIVE

NtCreateFile 调用 I/O 管理器函数 IoCreateFile,该函数又调用未记录的对象管理器 API ObOpenObjectByName。这完成了解析路径的工作。对象管理器以\??\C:\Temp\test.txt 开头。然后将其替换为\Global??\C:Temp\test.txt。接下来它解析到C: 符号链接,并且必须重新开始(重新解析)最终路径\Device\HarddiskVolume2\Temp\test.txt

一旦对象管理器获取到HarddiskVolume2 设备对象,解析就会移交给实现Device 对象类型的I/O 管理器。 I/O DeviceParseProcedure 创建 File 对象和带有 major function code IRP_MJ_CREATE 的 I/O Request Packet (IRP)(打开/创建操作)将由设备堆栈处理。这通过IoCallDriver 发送到设备驱动程序。如果设备实现了重解析点(例如连接挂载点、符号链接等)并且路径包含重解析点,则必须将解析的路径重新提交给对象管理器以从头开始解析。

设备驱动程序将使用SeChangeNotifyPrivilege(几乎总是存在并启用)的进程令牌(或线程,如果模拟)来绕过访问检查,同时遍历目录。但是,最终访问设备和目标文件必须由安全描述符允许,该描述符通过SeAccessCheck 进行验证。除了 FAT32 等简单文件系统不支持文件安全性。

【讨论】:

【参考方案2】:

以下是关于@Eryk Sun 解决方案的 Python 3 版本。

def winapi_path(dos_path, encoding=None):
    if (not isinstance(dos_path, str) and encoding is not None): 
        dos_path = dos_path.decode(encoding)
    path = os.path.abspath(dos_path)
    if path.startswith(u"\\\\"):
        return u"\\\\?\\UNC\\" + path[2:]
    return u"\\\\?\\" + path

#Python 3 将 unicode 类型重命名为 str,旧的 str 类型已被字节替换。 NameError: global name 'unicode' is not defined - in Python 3

【讨论】:

不幸的是,这个解决方案在我的情况下不起作用。我的路径也超过 259 个字符,MSYS (www.msys2.org) 中的 Python3 给了我“没有这样的文件或目录”错误。但是当我在 WSL(Linux 的 Windows 子系统)下的 Ubuntu 中运行相同的 python 脚本时,它可以工作。【参考方案3】:

您收到此错误的原因可能有多种。请确保以下几点:

    文件夹(JSONFiles)的父目录与Python脚本的目录相同。

    即使文件夹存在,也不意味着单个文件存在。验证相同并确保确切的文件名与您的 Python 代码尝试访问的文件名匹配。

如果您仍然遇到问题,请在您尝试访问的最里面的文件夹上分享“dir”命令的结果。

【讨论】:

关于你的第一个笔记,是的,我很确定。关于您的第二个注意事项,该文件夹中没有同名文件,我的脚本应该创建该文件。关于dir命令,请告诉我你想要什么脚本,我会执行并告诉你结果 当您共享代码时,我建议您使用 os.path.join() 命令加入您当前在 open 函数中连接的不同路径变量,然后您可以验证路径使用 os.path.exists()。 请检查我的新更新,它是关于路径的长度 路径名通常限制为 260 个字符,但您可以使用魔术前缀 '\\?\' 将其扩展到大约 32k。更多详情请咨询msdn.microsoft.com/en-us/library/… 请问我的路径应该如何?【参考方案4】:

添加帮助我解决类似问题的解决方案: python 版本 = 3.9,windows 版本 = 10 pro。

我遇到了文件名本身的问题,因为它对于 python 的 open 内置方法来说太长了。我得到的错误是路径根本不存在,尽管我使用'w+'模式打开(无论它是否存在都应该打开一个新文件)。

我发现这个guide 通过快速更改窗口的注册表编辑器(特别是组策略)解决了这个问题。向下滚动到“使 Windows 10 接受长文件路径”标题。

不要忘记更新您的操作系统组策略以立即生效,可以找到指南here。

希望这有助于将来的搜索,因为这篇文章已经很老了。

【讨论】:

以上是关于路径名太长无法打开?的主要内容,如果未能解决你的问题,请参考以下文章

信息:无法打开物理文件“路径”。操作错误5:“5(拒绝访问。)”(MICROSOFT SQL Server,错误:5120)

系统找不到指定的路径

无法退出太长的列表

eclipse 打开Android SDK Manager 是报这个错误 [SDK Manager] 系统找不到指定的路径。 不知道啥原因

windows路径太长无法删除

Windows中删除路径太长目录及文件