如何使用PIL读取Windows Shell Namespace路径文件的元数据?
解决PIL无法打开Windows Shell Namespace路径文件的问题
问题原因
Python标准库的builtins.open()(也就是PIL底层依赖的文件打开方式)只能识别常规本地文件系统路径,无法解析Windows Shell Namespace这类虚拟路径(比如你提供的iPhone设备图片路径)。这类路径是Windows Shell特有的虚拟命名空间,只有Windows资源管理器这类调用Shell API的程序才能直接访问。
解决方案
要处理这类路径,需要借助Windows Shell API来获取文件的真实路径或文件流,再传递给PIL。以下是两种可行方法:
方法一:通过pywin32获取文件流直接打开
使用pywin32库调用Windows Shell API解析路径,获取文件流后用PIL打开:
- 先安装依赖:
pip install pywin32 - 示例代码:
import win32com.client from PIL import Image import io # 去掉路径两端引号,处理转义 shell_path = "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\{55DE1ED1-3F3E-4C88-BC1A-819EFF0BE330}\\73cdac9ad5200bebf6ab95998c1bed571f70fd23\\PhotoLibrary\\photo_library.album.all_assets\\A2FD049A03544E90B70243069CB28014.JPG" # 初始化Shell对象 shell = win32com.client.Dispatch("Shell.Application") # 解析Shell路径获取文件项 file_item = shell.Namespace(0).ParseName(shell_path) try: # 优先尝试获取真实文件路径(部分虚拟路径可能有映射的真实路径) real_file_path = file_item.Path with Image.open(real_file_path) as img: exif_data = img.getexif() # 处理EXIF信息,示例为打印 print(exif_data) except Exception: # 若无法获取真实路径,直接读取文件流 file_stream = file_item.GetLink() if file_stream: # 将流写入内存字节对象 stream_content = io.BytesIO(file_stream.Read()) with Image.open(stream_content) as img: exif_data = img.getexif() print(exif_data) else: print("无法获取文件的真实路径或流")
方法二:复制文件到临时目录再处理
如果上述方法无法获取流,可将Shell命名空间中的文件复制到本地临时目录,再用PIL打开:
import win32com.client import tempfile import os from PIL import Image shell_path = "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\{55DE1ED1-3F3E-4C88-BC1A-819EFF0BE330}\\73cdac9ad5200bebf6ab95998c1bed571f70fd23\\PhotoLibrary\\photo_library.album.all_assets\\A2FD049A03544E90B70243069CB28014.JPG" shell = win32com.client.Dispatch("Shell.Application") file_item = shell.Namespace(0).ParseName(shell_path) # 创建临时目录,生成临时文件路径 temp_dir = tempfile.gettempdir() temp_file_path = os.path.join(temp_dir, file_item.Name) # 复制Shell中的文件到临时目录 shell.Namespace(temp_dir).CopyHere(file_item) # 用PIL打开临时文件并读取EXIF with Image.open(temp_file_path) as img: exif_data = img.getexif() print(exif_data) # 处理完成后删除临时文件 os.remove(temp_file_path)
内容的提问来源于stack exchange,提问作者Sergey Shabalin
相关产品推荐
相关产品推荐

