Windows超长路径下如何获取快捷方式的目标路径?
解决Windows超长路径下提取快捷方式目标路径的问题
你碰到的问题本质是WScript.Shell的CreateShortCut方法不支持超过260字符的超长路径——哪怕你后来给目标路径加了\\?\前缀,也没法解决打开lnk文件本身时的路径长度限制,因为第一步调用CreateShortCut就已经失败了。
下面给你两种可行的解决方案:
方法一:调用Windows原生API(通过ctypes实现)
Windows系统提供了专门处理快捷方式的原生API,能直接支持超长路径。我们可以用Python的ctypes库调用这些API,绕开WScript.Shell的限制。
示例代码如下:
import ctypes from ctypes import wintypes # 定义API所需的结构体 class SHORTCUTTARGETINFO(ctypes.Structure): _fields_ = [ ('cbSize', wintypes.DWORD), ('pwszTarget', wintypes.LPWSTR), ('cchTarget', wintypes.DWORD), ('pwszArguments', wintypes.LPWSTR), ('cchArguments', wintypes.DWORD), ('pwszWorkingDirectory', wintypes.LPWSTR), ('cchWorkingDirectory', wintypes.DWORD), ('dwFlags', wintypes.DWORD), ('dwHotkey', wintypes.DWORD), ('dwShowCmd', wintypes.DWORD), ('hIcon', wintypes.HICON), ('pwszIconLocation', wintypes.LPWSTR), ('cchIconLocation', wintypes.DWORD), ] # 加载shell32.dll并绑定API shell32 = ctypes.WinDLL('shell32', use_last_error=True) SHGetShortcutTargetInfoW = shell32.SHGetShortcutTargetInfoW SHGetShortcutTargetInfoW.argtypes = [wintypes.LPCWSTR, ctypes.POINTER(SHORTCUTTARGETINFO)] SHGetShortcutTargetInfoW.restype = wintypes.BOOL def get_lnk_target(lnk_path): # 给lnk路径添加超长路径前缀,确保Windows能识别 if not lnk_path.startswith('\\\\?\\'): lnk_path = '\\\\?\\' + lnk_path # 初始化结构体 sti = SHORTCUTTARGETINFO() sti.cbSize = ctypes.sizeof(SHORTCUTTARGETINFO) # 第一次调用获取缓冲区大小 if not SHGetShortcutTargetInfoW(lnk_path, ctypes.byref(sti)): error = ctypes.get_last_error() if error == 0x7A: # 错误码:缓冲区不足 # 分配足够的缓冲区空间 sti.cchTarget += 1 sti.pwszTarget = ctypes.create_unicode_buffer(sti.cchTarget) # 第二次调用获取目标路径 if SHGetShortcutTargetInfoW(lnk_path, ctypes.byref(sti)): return sti.pwszTarget.value raise ctypes.WinError(error) return sti.pwszTarget.value # 使用示例 fp = r'C:\very_long_path\to\a\link\file\shortcut.lnk' target_path = get_lnk_target(fp) print(target_path)
方法二:直接解析LNK文件的二进制结构
如果不想依赖系统API,也可以直接解析lnk文件的二进制格式(微软已公开LNK文件的规范)。这种方法完全靠读取文件内容提取目标路径,不需要调用任何Windows COM组件。
简化版示例代码(仅处理本地文件快捷方式):
import struct def parse_lnk_target(lnk_path): # 处理超长路径,确保能正常打开文件 if not lnk_path.startswith('\\\\?\\'): lnk_path = '\\\\?\\' + lnk_path with open(lnk_path, 'rb') as f: # 跳过文件头前20字节 f.seek(20) # 读取标志位,判断是否包含目标路径列表 flags = struct.unpack('<I', f.read(4))[0] has_link_target_id_list = (flags & 0x01) != 0 if not has_link_target_id_list: return None # 跳转到LinkTargetIDList区域 f.seek(0x4C) id_list_size = struct.unpack('<H', f.read(2))[0] f.seek(2, 1) # 跳过IDList的空起始项 # 解析Shell Item列表,提取文件路径 path_parts = [] remaining = id_list_size - 2 while remaining > 0: item_size = struct.unpack('<H', f.read(2))[0] remaining -= item_size item_data = f.read(item_size - 2) # 识别文件系统类型的Shell Item if item_data[0] == 0x31: # 提取UTF-16编码的路径片段 path = item_data[1:].decode('utf-16le').rstrip('\x00') path_parts.append(path) return '\\'.join(path_parts) # 使用示例 fp = r'C:\very_long_path\to\a\link\file\shortcut.lnk' target_path = parse_lnk_target(fp) print(target_path)
注意事项
- 方法一中的API仅支持Windows Vista及以上系统;
- 方法二的简化版只适配本地文件快捷方式,若需处理网络共享、特殊文件夹的快捷方式,需要扩展解析逻辑;
- 两种方法都需要给lnk文件路径添加
\\?\前缀,这是Windows识别超长路径的必要条件。
内容的提问来源于stack exchange,提问作者user2366975
相关产品推荐
相关产品推荐

