Windows上的符号链接?

38 python winapi symlink pywin32

有没有人知道从Python的win32版本中创建/读取符号链接的方法?理想情况下,应该有最少量的平台特定代码,因为我需要我的应用程序是跨平台的.

Anu*_*yal 37

NTFS文件系统有连接点,我想你可以使用它们,你可以使用python win32 API模块,例如

import win32file

win32file.CreateSymbolicLink(fileSrc, fileTarget, 1)
Run Code Online (Sandbox Code Playgroud)

如果您不想依赖win32API模块,您可以随时使用ctypes并直接调用CreateSymbolicLinkwin32 API,例如

import ctypes

kdll = ctypes.windll.LoadLibrary("kernel32.dll")

kdll.CreateSymbolicLinkA("d:\\test.txt", "d:\\test_link.txt", 0)
Run Code Online (Sandbox Code Playgroud)

MSDN(http://msdn.microsoft.com/en-us/library/aa363866 ( VS.85 ) .aspx)表示支持的最低客户端是Windows Vista

另外:这也适用于目录(用第三个参数表示).有了unicode支持,它看起来像这样:

kdll.CreateSymbolicLinkW(UR"D:\testdirLink", UR"D:\testdir", 1)
Run Code Online (Sandbox Code Playgroud)

另请参阅 在Python中创建NTFS连接点

  • 您不应该使用`..A` Windows API,而是每次使用`..W`(Unicode) - 即使在这样的示例中也是如此. (13认同)
  • 为了清楚起见:`win32file.CreateSymboleLink`的最后一个参数对于目录应为1,对于文件应为0. (4认同)
  • 为`win32file.CreateSymbolicLink`显示的参数名称有点令人困惑.对于那些想知道的人,第一个是要创建的链接的名称,第二个是它应该链接到的路径. (3认同)

Cha*_*ald 12

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 == 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()
Run Code Online (Sandbox Code Playgroud)

根据您的需要调整CreateFile中的属性,但对于正常情况,它应该可以工作.随意改进它.

如果您使用MOUNTPOINT而不是SYMBOLIC_LINK,它也适用于文件夹联结.

你可以检查一下

sys.getwindowsversion()[0] >= 6
Run Code Online (Sandbox Code Playgroud)

如果你把它放到你发布的东西上,因为这种形式的符号链接只在Vista +上支持.


Ale*_*lli 11

问题是,正如此处所解释的那样,Windows自身对符号链接功能的支持因Windows版本而异,因此,例如在Vista(有大量工作)中,您可以获得比XP或2000更多的功能(在其他方面没有AFAIK) win32版本).或者您可以使用快捷方式,当然这些快捷方式有一组限制,并且与"Unix"符号链接"并不相同".所以,你必须准确说明你需要什么功能,你愿意在交叉win32操作的祭坛上牺牲多少等等 - 那么,我们可以找出如何实现你所选择的折衷方案的ctypeswin32all来电...这是最低的了,在一定意义上.


Reh*_*aja 11

os.symlink适用于使用Windows 8.1和NTFS文件系统的Python 3.3.

  • 但它需要管理员权限:“WinError 1314:客户端不拥有所需的权限。” (2认同)

use*_*866 9

在子进程中使用mklink命令创建链接.

from subprocess import call
call(['mklink', 'LINK', 'TARGET'], shell=True)
Run Code Online (Sandbox Code Playgroud)


Dav*_*ard 7

我将以下内容放入Lib/site-packages/sitecustomize.py中

import os

__CSL = None
def symlink(source, link_name):
    '''symlink(source, link_name)
       Creates a symbolic link pointing to source named link_name'''
    global __CSL
    if __CSL is None:
        import ctypes
        csl = ctypes.windll.kernel32.CreateSymbolicLinkW
        csl.argtypes = (ctypes.c_wchar_p, ctypes.c_wchar_p, ctypes.c_uint32)
        csl.restype = ctypes.c_ubyte
        __CSL = csl
    flags = 0
    if source is not None and os.path.isdir(source):
        flags = 1
    if __CSL(link_name, source, flags) == 0:
        raise ctypes.WinError()

os.symlink = symlink
Run Code Online (Sandbox Code Playgroud)