这是执行的截图:
如您所见,错误表示目录" JSONFiles / Apartment / Rent / dubizzleabudhabiproperty"不存在。
但请查看我的文件:
该文件夹绝对存在。
代码
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
当我将文件名更改为较小的文件名时,它可以正常工作,因此问题在于路径的长度。请问是什么解决方案?
答案 0 :(得分:11)
常规DOS路径仅限于MAX_PATH
(260)个字符,包括字符串终止NUL
个字符。您可以使用以\\?\
前缀开头的扩展长度路径来超出此限制。此路径必须是Unicode字符串,完全限定,并且仅使用反斜杠作为路径分隔符。根据Microsoft的file system functionality comparison,最大扩展路径长度为32760个字符。单个文件或目录名最多可包含255个字符(UDF文件系统为127个字符)。扩展的UNC路径也支持\\?\UNC\server\share
。
例如:
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上的以下页面:
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
设备对象,解析就会传递给I / O管理器,后者实现Device
对象类型。 I / O ParseProcedure
的{{1}}创建Device
对象,I/O Request Packet (IRP)创建major function code File
(开放/创建操作)由设备堆栈处理。这将通过IoCallDriver
发送到设备驱动程序。如果设备实现重新分析点(例如结点安装点,符号链接等)并且路径包含重新分析点,则必须将已解析的路径重新提交到对象管理器以从头开始进行解析。
设备驱动程序将使用进程令牌的IRP_MJ_CREATE
(几乎始终存在并启用)(或模拟时的线程)在遍历目录时绕过访问检查。但是,安全描述符必须允许最终访问设备和目标文件,该描述符通过SeAccessCheck
进行验证。除了简单的文件系统,如FAT32,不支持文件安全。
答案 1 :(得分: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
答案 2 :(得分:0)
您收到此错误的原因可能有多种。请确认以下内容:
文件夹的父目录(JSONFiles)与Python脚本的目录相同。
即使文件夹存在,也不代表单个文件。验证相同并确保确切的文件名与Python代码尝试访问的文件名相匹配。
如果您仍然遇到问题,请在您尝试访问的最里面的文件夹中分享“dir”命令的结果。
答案 3 :(得分:0)