使用Python在默认应用程序中打开文档

Abd*_*aly 115 python windows macos

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

Nic*_*ick 136

使用subprocessPython 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))
Run Code Online (Sandbox Code Playgroud)

双括号是因为subprocess.call()想要一个序列作为它的第一个参数,所以我们在这里使用一个元组.在使用Gnome的Linux系统上,还有一个gnome-open执行相同操作的命令,但xdg-open它是Free Desktop Foundation标准,适用于Linux桌面环境.

  • 在subprocess.call()中使用'start'在Windows上不起作用 - start实际上不是可执行文件. (5认同)
  • 在Windows上启动是一个shell命令,而不是可执行文件.您可以使用subprocess.call(('start',filepath),shell = True),但如果您在shell中执行,也可以使用os.system. (5认同)
  • nitpick:在所有linuxen上(我猜大多数BSD)你应该使用`xdg-open` - http://linux.die.net/man/1/xdg-open (2认同)

Cha*_*tin 64

在Mac OS中,您可以使用"打开"命令.有一个类似的Windows API调用,但我不记得它.

更新

好的,"start"命令会这样做,所以这应该有效.

Mac OS/X:

subprocess.check_call(['open', filename])
Run Code Online (Sandbox Code Playgroud)

视窗:

subprocess.run(['open', filename], check=True)
Run Code Online (Sandbox Code Playgroud)

很多以后由Edward更新:os.system有效,但它只适用于文件夹中没有任何空格的文件名(例如A:\ abc\def\a.txt).

稍后更新

好吧,显然这个愚蠢的争议还在继续,所以让我们看看用子进程做这件事.

open并且start分别是Mac OS/X和Windows的命令解释器.现在,假设我们使用子进程.通常,你会使用:

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
Run Code Online (Sandbox Code Playgroud)

现在,这有什么好处?从理论上讲,这更安全 - 但实际上我们需要以某种方式执行命令行; 在任何一种环境中,我们都需要环境和服务来实现interpet,获取路径等等.在任何一种情况下我们都不执行任意文本,因此它没有固有的"但你可以输入subprocess"问题,如果文件名可能被破坏,使用就os.system()没有保护.

它实际上并没有给我们任何更多的错误检测,我们仍然依赖os.system于任何一种情况.我们不需要等待子进程,因为我们是通过问题声明开始一个单独的进程.

"但是os.system首选." 但是,A:\abc\def\a.txt不会弃用,它是这项特定工作的最简单工具.

结论:使用shlex.quote是最简单,最直接的方法,因此是正确的答案.

  • 我觉得有点不愿意重新开始这个讨论,但我认为"后期更新"部分完全错了.用`使用os.system的问题()`是它使用的外壳(和你没有做任何shell这里逃脱,那么糟糕的事情发生了这事发生在包含shell元字符完全有效的文件名).首选`subprocess.call()`的原因是你可以选择使用`subprocess.call(["open",filename])`来绕过shell.这适用于所有有效的文件名,即使对于不受信任的文件名,也不会引入shell注入漏洞. (20认同)
  • 当然重要.这是一个好答案和一个坏答案(或一个可怕的答案)之间的区别.os.system()的文档本身说"使用子进程模块".还需要什么?这对我来说已经足够了. (8认同)
  • 尼克的回答看起来很好.什么都没有阻碍.用错误的例子解释事情并不容易. (6认同)
  • 取决于`filename`的形式,这是os.system()不安全和不良的原因的完美示例.子进程更好. (2认同)
  • 与使用子进程相比,它不太安全且不够灵活.这对我来说听起来不对. (2认同)
  • 此类安全问题不仅影响原始程序员,不仅影响使用该程序的人员,还可能影响互联网上的每个人。您需要一个该死的合理理由来证明这样的教育捷径是正确的,而且由于这样做是微不足道的,所以没有任何借口。 (2认同)
  • 我遇到了文件名中奇怪字符(即 ![] 和空格)的问题,所以我必须执行 `subprocess.check_call(('start', '', filename), shell=True)` 启动的第一个参数是显然是标题。(如果返回码不为 0,check_call 会引发错误,在大多数情况下我更喜欢它而不是 `subprocess.call`)(nm 显然 `os.startfile` 是一个东西) (2认同)
  • 可能值得补充的是,在 Windows 上,如果文件名包含空格,您仍然可以使用 `os.system`:`os.system('start "" "' + filename + '"')` (`""`是必要的,以便 Windows 不会将文件名解释为新窗口的标题。) (2认同)

DrB*_*ney 40

我更喜欢:

os.startfile(path, 'open')
Run Code Online (Sandbox Code Playgroud)

请注意,此模块支持在其文件夹和文件中包含空格的文件名,例如

A:\abc\folder with spaces\file with-spaces.txt
Run Code Online (Sandbox Code Playgroud)

(python docs)'open'不必添加(这是默认值).文档特别提到这就像在Windows资源管理器中双击文件的图标一样.

此解决方案仅限Windows.

  • 这只是windoze. (4认同)

dF.*_*dF. 34

仅仅为了完整性(它不在问题中),xdg-open将在Linux上做同样的事情.

  • +1通常情况下,响应者不应回答未被问及的问题,但在这种情况下,我认为这对整个SO社区非常重要和有帮助. (5认同)

nos*_*klo 23

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])
Run Code Online (Sandbox Code Playgroud)

  • 相关的python bug:http://bugs.python.org/issue3177 - 提供一个很好的补丁,它可能会被接受=) (3认同)
  • 嗯,我不知道startfile.如果Mac和Linux版本的Python采用类似的语义,那将是很好的. (2认同)

etu*_*rdu 20

如果必须使用启发式方法,您可以考虑webbrowser.
它是标准库,尽管它的名称,它也会尝试打开文件:

请注意,在某些平台上,尝试使用此函数打开文件名可能会起作用并启动操作系统的关联程序.但是,既不支持也不便携.(参考)

我尝试了这个代码,它在Windows 7和Ubuntu Natty中运行良好:

import webbrowser
webbrowser.open("path_to_file")
Run Code Online (Sandbox Code Playgroud)

此代码也可以在Windows XP Professional中使用Internet Explorer 8正常工作.

  • https://docs.python.org/3/library/webbrowser.html#webbrowser.open "请注意,在某些平台上,尝试使用 [webbrowser.open(url)] 打开文件名可能会起作用并启动操作系统的相关程序。但是,这既不支持也不可移植。” (4认同)
  • 据我所知,这是迄今为止最好的答案.似乎是跨平台的,无需检查正在使用的平台或导入操作系统平台. (2认同)
  • @jonathanrocher:我看到了[源代码中的Mac支持](https://github.com/python/cpython/blob/78d05eb847c6b8fede08ca74bb59210c00e4c599/Lib/webbrowser.py#L626)。它使用“ open location”(打开位置),如果您将路径指定为有效的url,则应该可以使用。 (2认同)

Tom*_*vic 6

如果subprocess.call()要这样做,在Windows上应如下所示:

import subprocess
subprocess.call(('cmd', '/C', 'start', '', FILE_NAME))
Run Code Online (Sandbox Code Playgroud)

您不能只使用:

subprocess.call(('start', FILE_NAME))
Run Code Online (Sandbox Code Playgroud)

因为start 它不是可执行文件,而是cmd.exe程序的命令。这有效:

subprocess.call(('cmd', '/C', 'start', FILE_NAME))
Run Code Online (Sandbox Code Playgroud)

但前提是FILE_NAME中没有空格。

尽管subprocess.call方法en正确地引用了参数,但是该start命令具有相当奇怪的语法,其中:

start notes.txt
Run Code Online (Sandbox Code Playgroud)

除了:

start "notes.txt"
Run Code Online (Sandbox Code Playgroud)

第一个带引号的字符串应设置窗口的标题。为了使其与空格配合使用,我们必须执行以下操作:

start "" "my notes.txt"
Run Code Online (Sandbox Code Playgroud)

这就是上面代码的作用。


小智 5

开始不支持长路径名和空格。您必须将其转换为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 )
Run Code Online (Sandbox Code Playgroud)

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


小智 5

os.startfile(path, 'open')Windows下好,因为当目录中有空格时,os.system('start', path_name)无法正确打开应用程序,当目录中存在i18n时,os.system需要将unicode更改为Windows中控制台的编解码器。