有没有办法在Python中创build一个NTFS交接点? 我知道我可以调用junction实用程序,但最好不要依赖外部工具。
我在类似的问题上回答了这个问题 ,所以我会把我的答案复制到下面。 自写这个答案以来,我写了一个只有Python(如果你可以调用一个使用ctypes python-only的模块)模块来创建,读取和检查可以在这个文件夹中找到的结点。 希望有所帮助。
而且,与使用CreateSymbolicLinkA API的答案不同,链接的实现应该可以在任何支持联结的Windows版本上工作。 CreateSymbolicLinkA仅在Vista +中受支持。
回答:
python ntfslink扩展
或者如果你想使用pywin32,你可以使用前面提到的方法,并阅读,使用:
from win32file import * from winioctlcon import FSCTL_GET_REPARSE_POINT __all__ = ['islink','readlink'] # Win32file doesn't seem to have this attribute. FILE_ATTRIBUTE_REPARSE_POINT = 1024 # To make things easier. REPARSE_FOLDER = (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT) # For the parse_reparse_buffer function SYMBOLIC_LINK = 'symbolic' MOUNTPOINT = 'mountpoint' GENERIC = 'generic' def islink(fpath): """ Windows islink implementation. """ if GetFileAttributes(fpath) & REPARSE_FOLDER: return True return False def parse_reparse_buffer(original,reparse_type=SYMBOLIC_LINK): """ Implementing the below in Python: typedef struct _REPARSE_DATA_BUFFER { ULONG ReparseTag; USHORT ReparseDataLength; USHORT Reserved; union { struct { USHORT SubstituteNameOffset; USHORT SubstituteNameLength; USHORT PrintNameOffset; USHORT PrintNameLength; ULONG Flags; WCHAR PathBuffer[1]; } SymbolicLinkReparseBuffer; struct { USHORT SubstituteNameOffset; USHORT SubstituteNameLength; USHORT PrintNameOffset; USHORT PrintNameLength; WCHAR PathBuffer[1]; } MountPointReparseBuffer; struct { UCHAR DataBuffer[1]; } GenericReparseBuffer; } DUMMYUNIONNAME; } REPARSE_DATA_BUFFER,*PREPARSE_DATA_BUFFER; """ # Size of our data types SZULONG = 4 # sizeof(ULONG) SZUSHORT = 2 # sizeof(USHORT) # Our structure. # Probably a better way to iterate a dictionary in a particular order,# but I was in a hurry,unfortunately,so I used pkeys. buffer = { 'tag' : SZULONG,'data_length' : SZUSHORT,'reserved' : SZUSHORT,SYMBOLIC_LINK : { 'substitute_name_offset' : SZUSHORT,'substitute_name_length' : SZUSHORT,'print_name_offset' : SZUSHORT,'print_name_length' : SZUSHORT,'flags' : SZULONG,'buffer' : u'','pkeys' : [ 'substitute_name_offset','substitute_name_length','print_name_offset','print_name_length','flags',] },MOUNTPOINT : { 'substitute_name_offset' : SZUSHORT,GENERIC : { 'pkeys' : [],'buffer': '' } } # Header stuff buffer['tag'] = original[:SZULONG] buffer['data_length'] = original[SZULONG:SZUSHORT] buffer['reserved'] = original[SZULONG+SZUSHORT:SZUSHORT] original = original[8:] # Parsing k = reparse_type for c in buffer[k]['pkeys']: if type(buffer[k][c]) == int: sz = buffer[k][c] bytes = original[:sz] buffer[k][c] = 0 for b in bytes: n = ord(b) if n: buffer[k][c] += n original = original[sz:] # Using the offset and length's grabbed,we'll set the buffer. buffer[k]['buffer'] = original return buffer def readlink(fpath): """ Windows readlink implementation. """ # This wouldn't return true if the file didn't exist,as far as I kNow. if not islink(fpath): return None # Open the file correctly depending on the string type. handle = CreateFileW(fpath,GENERIC_READ,None,OPEN_EXISTING,FILE_FLAG_OPEN_REPARSE_POINT,0) if type(fpath) == unicode else CreateFile(fpath,0) # MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16384 = (16*1024) buffer = DeviceIoControl(handle,FSCTL_GET_REPARSE_POINT,16*1024) # Above will return an ugly string (byte array),so we'll need to parse it. # But first,we'll close the handle to our file so we're not locking it anymore. CloseHandle(handle) # Minimum possible length (assuming that the length of the target is bigger than 0) if len(buffer) < 9: return None # Parse and return our result. result = parse_reparse_buffer(buffer) offset = result[SYMBOLIC_LINK]['substitute_name_offset'] ending = offset + result[SYMBOLIC_LINK]['substitute_name_length'] rpath = result[SYMBOLIC_LINK]['buffer'][offset:ending].replace('x00','') if len(rpath) > 4 and rpath[0:4] == '\??\': rpath = rpath[4:] return rpath def realpath(fpath): from os import path while islink(fpath): rpath = readlink(fpath) if not path.isabs(rpath): rpath = path.abspath(path.join(path.dirname(fpath),rpath)) fpath = rpath return fpath def example(): from os import system,unlink system('cmd.exe /c echo Hello World > test.txt') system('mklink test-link.txt test.txt') print 'IsLink: %s' % islink('test-link.txt') print 'ReadLink: %s' % readlink('test-link.txt') print 'RealPath: %s' % realpath('test-link.txt') unlink('test-link.txt') unlink('test.txt') if __name__=='__main__': example()
根据需要调整CreateFile中的属性,但对于正常情况,它应该可以工作。 随意改善它。
如果您使用MOUNTPOINT而不是SYMBOLIC_LINK,它也应该用于文件夹连接。
你可以检查一下
sys.getwindowsversion()[0] >= 6
如果你把这个东西放到你要发布的东西,因为这种形式的符号链接只支持Vista +。
你可以使用Python的Win32 API模块,例如
import win32file win32file.CreateSymbolicLink(srcDir,targetDir,1)
有关更多详细信息,请参见http://docs.activestate.com/activepython/2.5/pywin32/win32file__CreateSymbolicLink_meth.html
如果你不想依赖这个,你可以随时使用ctypes并直接调用CreateSymbolicLinl win32 API,这是一个简单的调用
这里是使用ctypes的示例调用
import ctypes kdll = ctypes.windll.LoadLibrary("kernel32.dll") kdll.CreateSymbolicLinkA("d:testdir","d:testdir_link",1)
MSDN说最低支持客户端Windows Vista
由于Python 3.5在_winapi模块中有一个函数CreateJunction 。
import _winapi _winapi.CreateJunction(source,target)
你不想依靠外部工具,但你不介意依赖于特定的环境? 我想你可以放心地假设,如果你使用的是NTFS,那么联结工具可能就在那里。
但是,如果你的意思是你不想打电话给外部程序,我发现这个ctypes是非常宝贵的东西。 它允许你直接从Python调用Windows DLL。 而且我很确定它现在是在标准的Python版本中。
你只需要找出哪个Windows DLL的CreateJunction() (或任何Windows调用它)的API调用,并设置参数和调用。 运气好的话,微软似乎不太支持。 您可以拆卸linkd junction程序或linkd或其他工具之一,以了解他们是如何做到的。
我,我很懒,我只是把junction叫做外部过程:-)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。