在Python中创buildNTFS连接点

有没有办法在Python中创build一个NTFS交接点? 我知道我可以调用junction实用程序,但最好不要依赖外部工具。

Solutions Collecting From Web of "在Python中创buildNTFS连接点"

我在类似的问题上回答了这个问题 ,所以我会把我的答案复制到下面。 自写这个答案以来,我写了一个只有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, 'substitute_name_length' : SZUSHORT, 'print_name_offset' : SZUSHORT, 'print_name_length' : SZUSHORT, 'buffer' : u'', 'pkeys' : [ 'substitute_name_offset', 'substitute_name_length', 'print_name_offset', 'print_name_length', ] }, 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, 0, None, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT, 0) \ if type(fpath) == unicode else \ CreateFile(fpath, GENERIC_READ, 0, None, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT, 0) # MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16384 = (16*1024) buffer = DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, None, 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叫做外部过程:-)