【问题标题】:How can I iterate across the photos on my connected iPhone from Windows 7 in Python?如何在 Python 中从 Windows 7 遍历连接的 iPhone 上的照片?
【发布时间】:2014-12-21 20:10:55
【问题描述】:

当我将我的 iPhone 连接到我的 Windows 7 系统时,Windows 资源管理器会打开一个包含 DCIM 内容的虚拟文件夹。我可以通过 Pywin32 (218) 访问 shell 库接口,如下所述:Can I use library abstractions in python?

给定一个在 Windows 资源管理器中工作的面向用户的编辑路径 (SIGDN_DESKTOPABSOLUTEEDITING),并启动 Windows 照片查看器:

计算机\我的 iPhone\内部存储\DCIM\828RTETC\IMG_2343.JPG

如何获取解析路径 (SIGDN_DESKTOPABSOLUTEPARSING) 以与 SHCreateItemFromParsingName() 一起使用以创建 ShellItem? (从中我会绑定一个流并复制到本地磁盘,如下所示:Can images be read from an iPhone programatically using CreateFile in Windows?

from win32com.shell import shell

edit_path = r'Computer\My iPhone\Internal Storage\DCIM\828RTETC\IMG_2343.JPG'
parse_path = # How to convert edit_path to a SIGDN_DESKTOPABSOLUTEPARSING path?
i = shell.SHCreateItemFromParsingName(parse_path, None, shell.IID_IShellItem)

最终目标是通过类似 IShellFolder 接口的方式迭代 DCIM“文件夹”,并将最近的照片复制到本地磁盘。我不想为解析名称打开 FileOpenDialog。但在此之前,我认为为其中一个文件创建一个 ShellItem 将是一个很好的测试。

【问题讨论】:

  • 便携式设备的解析名称是嵌入 USB 总线信息的长字符串。枚举计算机文件夹并找到一个以“我的 iPhone”为标签的项目可能更容易,而不是尝试找出如何为其生成解析名称。

标签: python iphone windows winapi


【解决方案1】:

我认为@jonathan-potter 的建议不是从编辑名称转换为解析名称,而是一种更好的方法。这是一个硬编码的 sn-p,它显示了如何从 Desktop 文件夹开始并排除错误处理:

from win32com.shell import shell, shellcon

desktop = shell.SHGetDesktopFolder()
for pidl in desktop:
    if desktop.GetDisplayNameOf(pidl, shellcon.SHGDN_NORMAL) == "Computer":
        break
folder = desktop.BindToObject(pidl, None, shell.IID_IShellFolder)
for pidl in folder:
     if folder.GetDisplayNameOf(pidl, shellcon.SHGDN_NORMAL) == "My iPhone":
         break
folder = folder.BindToObject(pidl, None, shell.IID_IShellFolder)
for pidl in folder:
    if folder.GetDisplayNameOf(pidl, shellcon.SHGDN_NORMAL) == "Internal Storage":
        break
# And so on...

【讨论】:

  • 好问题@David!您能否添加更多详细信息以显示如何在“计算机\我的 iPhone\内部存储\DCIM”中浏览并最终将文件从那里复制到本地目录?提前非常感谢!我会为此开始赏金。
  • 有人知道怎么做吗?太烦人了,我可以得到所有文件和文件夹的名称,但似乎没有任何方法可以使用 PIDL 实际复制文件!
  • 在尝试此解决方案并失败后,结果表明 import 语句现在应为“from win32comext.shell import shell, shellcon”
【解决方案2】:

感谢以上信息,有了它,我能够制作一个 python 实现,用于将照片从 iPhone X 移动到 Windows10 PC。以下主要功能

# imports probably needed
from win32com.shell import shell, shellcon
from win32com.propsys import propsys
import pythoncom

# Recursive function to browse into a non filesystem path
def recurse_and_get_ishellfolder(base_ishellfolder, path):
    splitted_path = path.split("\\", 1)

    for pidl in base_ishellfolder:
        if base_ishellfolder.GetDisplayNameOf(pidl, shellcon.SHGDN_NORMAL) == splitted_path[0]:
            break

    folder = base_ishellfolder.BindToObject(pidl, None, shell.IID_IShellFolder)

    if len(splitted_path) > 1:
        # More to recurse
        return recurse_and_get_ishellfolder(folder, splitted_path[1])
    else:
        return folder


# How to move non filesystem file to filesystem patj
def move_file_by_pidl_to_path(src_ishellfolder, src_pidl, dst_path, dst_filename):
    pidl_folder_dst, flags = shell.SHILCreateFromPath(dst_path, 0)
    dst_ishellfolder = shell.SHGetDesktopFolder().BindToObject(pidl_folder_dst, None, shell.IID_IShellFolder)

    fidl = shell.SHGetIDListFromObject(src_ishellfolder)  # Grab the PIDL from the folder object
    didl = shell.SHGetIDListFromObject(dst_ishellfolder)  # Grab the PIDL from the folder object

    si = shell.SHCreateShellItem(fidl, None, src_pidl)  # Create a ShellItem of the source file
    dst = shell.SHCreateItemFromIDList(didl)

    pfo = pythoncom.CoCreateInstance(shell.CLSID_FileOperation, None, pythoncom.CLSCTX_ALL, shell.IID_IFileOperation)
    pfo.SetOperationFlags(shellcon.FOF_NOCONFIRMATION | shellcon.FOF_SILENT | shellcon.FOF_NOERRORUI)
    pfo.MoveItem(si, dst, dst_filename) # Schedule an operation to be performed
    pfo.PerformOperations()
    return not pfo.GetAnyOperationsAborted()


# Bonus: get file modification datetime for a non filesystem file
DATE_PROP_KEY = propsys.PSGetPropertyKeyFromName("System.DateModified")
DATE_PROP_PARSE_STR = '%Y/%m/%d:%H:%M:%S.%f' # not sure bout the f modifier but it does not really matter
def getmodified_datetime_by_pidl(src_ishellfolder, src_pidl):
    fidl = shell.SHGetIDListFromObject(src_ishellfolder)  # Grab the PIDL from the folder object
    si = shell.SHCreateShellItem(fidl, None, src_pidl)  # Create a ShellItem of the source file
    ps = propsys.PSGetItemPropertyHandler(si)
    date_str = ps.GetValue(DATE_PROP_KEY).ToString()
    return datetime.strptime(date_str, DATE_PROP_PARSE_STR)


# Example photo moving main logic
def move_files():
    main_folder = recurse_and_get_ishellfolder(shell.SHGetDesktopFolder(), "This Pc\\path\\to\\DCIM")

    for photo_folder_pidl in main_folder:
        folder_name = main_folder.GetDisplayNameOf(photo_folder_pidl, shellcon.SHGDN_NORMAL)
        folder = main_folder.BindToObject(photo_folder_pidl, None, shell.IID_IShellFolder)
        for pidl in folder:
            child_name = folder.GetDisplayNameOf(pidl, shellcon.SHGDN_NORMAL)

            file_mod_date = getmodified_datetime_by_pidl(folder, pidl)
            if not older_than_datetime or file_mod_date < older_than_datetime:
                print("Transferring file: " + child_name)
                move_file_by_pidl_to_path(...)
            else:
                print("Skipping too recent file: " + child_name)

移动照片的完整脚本: https://gitlab.com/lassi.niemisto/iphone-photo-dump

编辑:链接实现的关键部分在此处复制为代码

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多