如何在Windows资源管理器中打开指定文件夹并选中多个项目
实现Windows资源管理器定位文件夹并多选项目
问题场景
已知文件夹路径:
dir_: str = r'path\to\a\folder'
以及该文件夹内的项目列表(不含路径):
items: list[str] = [ 'foo.py', 'bar.exe', 'baz' ]
需要打开Windows资源管理器,定位到dir_并选中列表中所有项目。尝试过subprocess调用explorer /select命令,但该命令仅支持选中单个项目。
解决方案
方法一:使用pywin32库(需额外安装)
先安装依赖:
pip install pywin32
实现代码:
import os import win32com.client dir_ = r'path\to\a\folder' items = ['foo.py', 'bar.exe', 'baz'] # 生成每个项目的完整路径 full_item_paths = [os.path.join(dir_, item) for item in items] # 初始化Shell对象 shell = win32com.client.Dispatch("Shell.Application") # 打开文件夹并选中第一个项目 shell.ShellExecuteEx( Verb="open", File=dir_, Parameters=f"/select,{full_item_paths[0]}", Show=1 ) # 遍历选中剩余项目 folder = shell.NameSpace(dir_) for path in full_item_paths[1:]: item = folder.ParseName(os.path.basename(path)) item.InvokeVerb("select")
说明:先通过ShellExecuteEx打开目标文件夹并选中第一个项目,再通过Shell对象的NameSpace方法获取文件夹对象,逐个选中剩余项目。
方法二:使用ctypes(无需额外依赖)
直接调用Windows Shell API,无需安装第三方库:
import os import ctypes from ctypes import wintypes # 定义Windows API所需的结构和常量 SHCONT = wintypes.DWORD SIGDN = wintypes.DWORD SEE_MASK_INVOKEIDLIST = 0x0000000C SIGDN_FILESYSPATH = 0x80058000 class SHELLEXECUTEINFO(ctypes.Structure): _fields_ = [ ("cbSize", wintypes.DWORD), ("fMask", wintypes.DWORD), ("hwnd", wintypes.HWND), ("lpVerb", wintypes.LPCWSTR), ("lpFile", wintypes.LPCWSTR), ("lpParameters", wintypes.LPCWSTR), ("lpDirectory", wintypes.LPCWSTR), ("nShow", wintypes.INT), ("hInstApp", wintypes.HINSTANCE), ("lpIDList", wintypes.LPVOID), ("lpClass", wintypes.LPCWSTR), ("hkeyClass", wintypes.HKEY), ("dwHotKey", wintypes.DWORD), ("hIconOrMonitor", wintypes.HANDLE), ("hProcess", wintypes.HANDLE) ] class IShellFolder(ctypes.Structure): _fields_ = [ ("QueryInterface", ctypes.CFUNCTYPE(wintypes.HRESULT, wintypes.LPCVOID, ctypes.POINTER(wintypes.LPVOID))), ("AddRef", ctypes.CFUNCTYPE(wintypes.ULONG)), ("Release", ctypes.CFUNCTYPE(wintypes.ULONG)), ("ParseDisplayName", ctypes.CFUNCTYPE(wintypes.HRESULT, wintypes.HWND, wintypes.LPCVOID, wintypes.LPCWSTR, ctypes.POINTER(wintypes.ULONG), ctypes.POINTER(wintypes.LPITEMIDLIST), ctypes.POINTER(wintypes.DWORD))), ("EnumObjects", ctypes.CFUNCTYPE(wintypes.HRESULT, wintypes.HWND, SHCONT, ctypes.POINTER(wintypes.LPVOID))), ("BindToObject", ctypes.CFUNCTYPE(wintypes.HRESULT, wintypes.LPITEMIDLIST, wintypes.LPCVOID, wintypes.LPCVOID, ctypes.POINTER(wintypes.LPVOID))), ("BindToStorage", ctypes.CFUNCTYPE(wintypes.HRESULT, wintypes.LPITEMIDLIST, wintypes.LPCVOID, wintypes.LPCVOID, ctypes.POINTER(wintypes.LPVOID))), ("CompareIDs", ctypes.CFUNCTYPE(wintypes.HRESULT, SHCONT, wintypes.LPITEMIDLIST, wintypes.LPITEMIDLIST)), ("CreateViewObject", ctypes.CFUNCTYPE(wintypes.HRESULT, wintypes.HWND, wintypes.LPCVOID, ctypes.POINTER(wintypes.LPVOID))), ("GetAttributesOf", ctypes.CFUNCTYPE(wintypes.HRESULT, wintypes.ULONG, wintypes.LPITEMIDLIST*, ctypes.POINTER(wintypes.DWORD))), ("GetUIObjectOf", ctypes.CFUNCTYPE(wintypes.HRESULT, wintypes.HWND, wintypes.ULONG, wintypes.LPITEMIDLIST*, wintypes.LPCVOID, wintypes.DWORD, ctypes.POINTER(wintypes.LPVOID))), ("GetDisplayNameOf", ctypes.CFUNCTYPE(wintypes.HRESULT, wintypes.LPITEMIDLIST, SIGDN, ctypes.POINTER(wintypes.LPWSTR))), ("SetNameOf", ctypes.CFUNCTYPE(wintypes.HRESULT, wintypes.HWND, wintypes.LPITEMIDLIST, wintypes.LPCWSTR, SIGDN, ctypes.POINTER(wintypes.LPITEMIDLIST))) ] # 加载Windows API函数 SHGetDesktopFolder = ctypes.windll.shell32.SHGetDesktopFolder SHGetDesktopFolder.argtypes = [ctypes.POINTER(wintypes.IShellFolder)] SHGetDesktopFolder.restype = wintypes.HRESULT ShellExecuteExW = ctypes.windll.shell32.ShellExecuteExW ILFree = ctypes.windll.shell32.ILFree def select_multiple_items(dir_path, item_names): if not item_names: # 无项目时直接打开文件夹 ctypes.windll.shell32.ShellExecuteW(None, "open", dir_path, None, None, 1) return # 打开文件夹并选中第一个项目 sei = SHELLEXECUTEINFO() sei.cbSize = ctypes.sizeof(SHELLEXECUTEINFO) sei.fMask = SEE_MASK_INVOKEIDLIST sei.lpVerb = "open" sei.lpFile = dir_path sei.lpParameters = f"/select,{os.path.join(dir_path, item_names[0])}" sei.nShow = 1 ShellExecuteExW(ctypes.byref(sei)) # 获取桌面Shell文件夹接口 desktop_folder = IShellFolder() SHGetDesktopFolder(ctypes.byref(desktop_folder)) # 解析文件夹路径为ITEMIDLIST folder_pidl = wintypes.LPITEMIDLIST() ch_eaten = wintypes.ULONG() attrs = wintypes.DWORD() desktop_folder.ParseDisplayName(None, None, dir_path, ctypes.byref(ch_eaten), ctypes.byref(folder_pidl), ctypes.byref(attrs)) # 绑定到目标文件夹的IShellFolder接口 target_folder = IShellFolder() desktop_folder.BindToObject(folder_pidl, None, ctypes.byref(ctypes.c_void_p.from_address(ctypes.addressof(target_folder))), None) # 选中剩余项目 for name in item_names[1:]: item_pidl = wintypes.LPITEMIDLIST() target_folder.ParseDisplayName(None, None, name, ctypes.byref(ch_eaten), ctypes.byref(item_pidl), ctypes.byref(attrs)) # 调用select动词选中项目 target_folder.GetUIObjectOf(None, 1, ctypes.byref(item_pidl), None, 0, None) ILFree(item_pidl) # 释放资源 ILFree(folder_pidl) desktop_folder.Release() target_folder.Release() # 使用示例 dir_ = r'path\to\a\folder' items = ['foo.py', 'bar.exe', 'baz'] select_multiple_items(dir_, items)
说明:直接调用Windows底层Shell API,先打开文件夹选中第一个项目,再通过解析项目路径获取对应的Shell对象,逐个选中剩余项目,无需额外安装依赖。
注意事项
- 确保
items中的所有项目都存在于dir_路径下,不存在的项目无法被选中。 - 如果
items为空,建议直接打开文件夹,避免代码报错。
内容的提问来源于stack exchange,提问作者Megacodist
相关产品推荐
相关产品推荐

