这是执行的屏幕截图:
正如你所看到的,错误说目录“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
当我将文件名更改为较小的文件名时,它可以正常工作,所以问题在于path的长度。 请问有什么解决办法?
常规的DOS路径限于MAX_PATH
(260)个字符,包括字符串的终止NUL
字符。 您可以通过使用以\\?\
前缀开头的扩展路径来超过此限制。 此路径必须是Unicode字符串,完全限定,并且只能使用反斜杠作为路径分隔符。 根据微软的文件系统功能比较 ,最大扩展路径长度是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)开始,这变成了虚拟前缀。 对象管理器通过首先检查目录\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 Device
的ParseProcedure
创建File
对象和I / O请求包(IRP) ,其主要功能代码为 IRP_MJ_CREATE
(一个开放/创建操作),由设备堆栈处理。 这通过IoCallDriver
发送到设备驱动程序。 如果设备实现重新分析点(例如连接点挂载点,符号链接等),并且路径包含重新分析点,则解析的路径必须重新提交给对象管理器,以便从头开始解析。
设备驱动程序将使用进程标记(或模拟的线程)的SeChangeNotifyPrivilege
(几乎总是存在并启用)来绕过SeChangeNotifyPrivilege
目录的访问检查。 但是,最终必须通过安全描述符来访问设备和目标文件,并通过SeAccessCheck
进行验证。 除了简单的文件系统如FAT32不支持文件安全。
你得到这个错误有多种原因。 请确保以下内容:
文件夹的父目录(JSONFiles)与Python脚本的目录相同。
即使该文件夹存在,它并不意味着个人文件。 验证相同,并确保确切的文件名称匹配您的Python代码试图访问的名称。
如果您仍然遇到问题,请在您尝试访问的最里面的文件夹上共享“dir”命令的结果。