在Windows和Mac操作系统中,使用Python中的默认操作系统应用程序打开文档

在Windows和Mac操作系统中,使用Python中的默认操作系统应用程序打开文档,python,windows,macos,Python,Windows,Macos,我需要能够在Windows和Mac OS中使用默认应用程序打开文档。基本上,我想做的事情与在Explorer或Finder中双击文档图标时发生的事情相同。在Python中执行此操作的最佳方法是什么?open和start分别是用于Mac OS/X和Windows的命令解释器 要从Python中调用它们,您可以使用子流程模块或os.system() 以下是使用哪个软件包的注意事项: 您可以通过os.system调用它们,这很有效,但是 转义:os.system仅适用于路径名中没有空格或其他shell

我需要能够在Windows和Mac OS中使用默认应用程序打开文档。基本上,我想做的事情与在Explorer或Finder中双击文档图标时发生的事情相同。在Python中执行此操作的最佳方法是什么?

open
start
分别是用于Mac OS/X和Windows的命令解释器

要从Python中调用它们,您可以使用
子流程
模块或
os.system()

以下是使用哪个软件包的注意事项:

  • 您可以通过
    os.system
    调用它们,这很有效,但是

    转义:
    os.system
    仅适用于路径名中没有空格或其他shell元字符的文件名(例如
    A:\abc\def\A.txt
    ),否则这些文件名需要转义。对于类Unix系统有
    shlex.quote
    ,但对于Windows没有真正的标准。也许你也会看到

    • MacOS/X:
      os.system(“打开”+shlex.quote(文件名))
    • Windows:
      os.system(“开始”+filename)
      这里正确地说
      filename
      也应该转义
  • 您也可以通过
    子流程
    模块调用它们,但是

    对于Python2.7及更新版本,只需使用

    subprocess.check_call(['open', filename])
    
    在Python3.5+中,您可以等效地使用稍微复杂一些但也有点通用的

    subprocess.run(['open', filename], check=True)
    
    如果您需要一直兼容Python 2.4,可以使用
    subprocess.call()
    并实现您自己的错误检查:

    try:
        retcode = subprocess.call("open " + filename, shell=True)
        if retcode < 0:
            print >>sys.stderr, "Child was terminated by signal", -retcode
        else:
            print >>sys.stderr, "Child returned", retcode
    except OSError, e:
        print >>sys.stderr, "Execution failed:", e
    
    试试看:
    retcode=subprocess.call(“打开”+文件名,shell=True)
    如果retcode<0:
    打印>>sys.stderr,“子项被信号终止”,-retcode
    其他:
    打印>>sys.stderr,“返回的子对象”,重新编码
    除O错误外,e:
    打印>>sys.stderr,“执行失败:”,e
    
    现在,使用
    子流程的优点是什么

    • 安全性:理论上,这更安全,但实际上我们需要以这种或那种方式执行命令行;在这两种环境中,我们都需要环境和服务来解释、获取路径等等。在这两种情况下,我们都不会执行任意文本,因此它没有固有的“但是您可以键入
      'filename;rm-rf/'
      ”问题,并且如果
      文件名可能损坏,则使用
      子进程。call
      几乎不会给我们额外的保护
    • 错误处理:它实际上没有给我们更多的错误检测,我们仍然依赖于
      retcode
      ;但是在发生错误的情况下显式引发异常的行为肯定会帮助您注意到是否存在故障(尽管在某些情况下,回溯可能不会比简单地忽略错误更有帮助)
    • 生成一个(非阻塞)子进程:我们不需要等待子进程,因为我们是通过问题陈述启动一个单独的进程
    对于反对意见,“但是
    子流程
    是首选的。”然而,
    os.system()
    并没有被弃用,从某种意义上说,它是这个特定作业最简单的工具。结论:因此,使用
    os.system()
    也是正确的答案

    一个明显的缺点是Windows
    start
    命令要求您传入
    shell=True
    ,这否定了使用
    子流程
    的大部分好处


  • 在mac os上,您可以调用
    open

    import os
    os.open("open myfile.txt")
    
    这将使用TextEdit打开文件,或者任何设置为此文件类型默认值的应用程序。

    我更喜欢:

    os.startfile(path, 'open')
    
    请注意,此模块支持文件夹和文件中有空格的文件名,例如

    A:\abc\folder with spaces\file with-spaces.txt
    
    ()不必添加“打开”(这是默认设置)。文档特别提到,这就像在Windows资源管理器中双击文件图标一样


    此解决方案仅适用于windows。

    仅为了完整性(这不是问题),将在Linux上执行相同的操作。

    使用Python 2.4+上可用的
    子进程
    模块,而不是
    os.system()
    ,因此您不必处理shell转义

    import subprocess, os, platform
    if platform.system() == 'Darwin':       # macOS
        subprocess.call(('open', filepath))
    elif platform.system() == 'Windows':    # Windows
        os.startfile(filepath)
    else:                                   # linux variants
        subprocess.call(('xdg-open', filepath))
    

    双括号是因为
    subprocess.call()
    需要一个序列作为其第一个参数,所以我们在这里使用元组。在使用GNOME的Linux系统中,还有一个<>代码> GNOME打开< /C>命令,它做同样的事情,但是<代码> XDG OPEN 是免费的桌面基础标准,它在Linux桌面环境下工作。

    < P>如果您想指定应用程序在Mac OS X上打开文件,请使用:
    import os
    import subprocess
    
    def click_on_file(filename):
        '''Open document with default application in Python.'''
        try:
            os.startfile(filename)
        except AttributeError:
            subprocess.call(['open', filename])
    

    os.system(“打开-a[app name][file name]”

    如果您想使用
    子流程.call()
    方式,在Windows上应该是这样的:

    import subprocess
    subprocess.call(('cmd', '/C', 'start', '', FILE_NAME))
    
    你不能只使用:

    subprocess.call(('start', FILE_NAME))
    
    因为
    start
    cmd.exe
    程序的命令。这项工作:

    subprocess.call(('cmd', '/C', 'start', FILE_NAME))
    
    但前提是文件名中没有空格

    subprocess.call
    方法正确引用参数时,
    start
    命令的语法相当奇怪,其中:

    start notes.txt
    
    做一些其他事情,而不是:

    start "notes.txt"
    
    第一个带引号的字符串应该设置窗口的标题。要使其与空间协同工作,我们必须做到:

    start "" "my notes.txt"
    

    这就是上面的代码所做的。

    Start不支持长路径名和空格。您必须将其转换为8.3兼容路径

    import subprocess
    import win32api
    
    filename = "C:\\Documents and Settings\\user\\Desktop\file.avi"
    filename_short = win32api.GetShortPathName(filename)
    
    subprocess.Popen('start ' + filename_short, shell=True )
    

    该文件必须存在才能使用API调用。

    我已经很晚了,但这里有一个使用windows API的解决方案。这将始终打开关联的应用程序

    import ctypes
    
    shell32 = ctypes.windll.shell32
    file = 'somedocument.doc'
    
    shell32.ShellExecuteA(0,"open",file,0,0,5)
    
    很多神奇的常数。第一个零是当前程序的hwnd。可以是零。其他两个零是可选参数(参数和目录)。5==SW_SHOW,它指定如何执行应用程序。 阅读
    了解更多信息。

    如果必须使用启发式方法
    import webbrowser
    webbrowser.open("path_to_file")
    
    subprocess.call('cmd /c start "" "any file path with spaces"')
    
    import sys, os, subprocess
    subprocess.call(('cmd /c start "" "'+ filepath +'"') if os.name is 'nt' else ('open' if sys.platform.startswith('darwin') else 'xdg-open', filepath))