我需要能够使用Windows和Mac OS中的默认应用程序打开文档。基本上,我想做同样的事情,当你双击资源管理器或Finder中的文档图标时发生的事情。在Python中执行此操作的最佳方法是什么?
答案 0 :(得分:132)
使用Python 2.4+上提供的subprocess
模块,而不是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-open
命令执行相同的操作,但xdg-open
是Free Desktop Foundation标准,适用于Linux桌面环境。
答案 1 :(得分:57)
open
和start
分别是Mac OS / X和Windows的命令解释器,用于执行此操作。
要从Python调用它们,您可以使用subprocess
模块或os.system()
。
以下是使用哪个包的注意事项:
您可以通过os.system
来调用它们,但是......
转义: os.system
仅适用于路径名中没有任何空格或其他shell元字符的文件名(例如A:\abc\def\a.txt
),否则这些必须是逃过一劫。类似Unix的系统有shlex.quote
,但没有什么真正适合Windows。也许还可以参见python, windows : parsing command lines with shlex
os.system("open " + shlex.quote(filename))
os.system("start " + filename)
正确说法filename
也应该被转义。您也可以通过subprocess
模块调用它们,但是......
对于Python 2.7及更高版本,只需使用
即可subprocess.check_call(['open', filename])
在Python 3.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
现在,使用subprocess
有什么好处?
'filename ; rm -rf /'
”问题,而如果文件名可能会被破坏,使用{{1为我们提供了额外的保护。subprocess.call
;但是在出现错误的情况下显式引发异常的行为肯定会帮助您注意到是否存在故障(尽管在某些情况下,回溯可能根本不会比简单地忽略错误更有帮助。)反对意见“但retcode
是首选。”但是,subprocess
并未弃用,从某种意义上说,它是这项特定工作的最简单工具。结论:因此使用os.system()
也是正确的答案。
标记为缺点的是,os.system()
命令要求传入start
,否定了使用shell=True
带来的大部分好处1}}。
答案 2 :(得分:33)
我更喜欢:
os.startfile(path, 'open')
请注意,此模块支持在其文件夹和文件中包含空格的文件名,例如
A:\abc\folder with spaces\file with-spaces.txt
(python docs)'open'不必添加(这是默认值)。文档特别提到这就像在Windows资源管理器中双击文件的图标一样。
此解决方案仅限Windows。
答案 3 :(得分:31)
仅仅为了完整性(问题不在其中),xdg-open将在Linux上执行相同操作。
答案 4 :(得分:21)
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])
答案 5 :(得分:19)
如果必须使用启发式方法,可以考虑webbrowser
它的标准库,尽管它的名称,它也会尝试打开文件:
请注意,在某些平台上,尝试使用此方法打开文件名 功能,可以工作并启动操作系统的关联 程序。但是,既不支持也不便携。 (Reference)
我试过这段代码,它在Windows 7和Ubuntu Natty中运行良好:
import webbrowser
webbrowser.open("path_to_file")
此代码在Windows XP Professional中也可以使用Internet Explorer 8正常工作。
答案 6 :(得分:4)
如果你想采用subprocess.call()
方式,它应该在Windows上看起来像这样:
import subprocess
subprocess.call(('cmd', '/C', 'start', '', FILE_NAME))
你不能只使用:
subprocess.call(('start', FILE_NAME))
因为start
is not an executable而是cmd.exe
程序的命令。这有效:
subprocess.call(('cmd', '/C', 'start', FILE_NAME))
但仅限FILE_NAME中没有空格。
虽然subprocess.call
方法 en 正确引用参数,但start
命令的语法相当奇怪,其中:
start notes.txt
做的不是:
start "notes.txt"
第一个引用的字符串应该设置窗口的标题。为了使它适用于空格,我们必须这样做:
start "" "my notes.txt"
这就是顶部的代码。
答案 7 :(得分:4)
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调用。
答案 8 :(得分:2)
我已经很晚了,但这是一个使用windows api的解决方案。这始终会打开相关的应用程序。
import ctypes
shell32 = ctypes.windll.shell32
file = 'somedocument.doc'
shell32.ShellExecuteA(0,"open",file,0,0,5)
很多魔法常数。第一个零是当前程序的hwnd。可以为零。另外两个零是可选参数(参数和目录)。 5 == SW_SHOW,它指定如何执行应用程序。 阅读 ShellExecute API docs了解更多信息。
答案 9 :(得分:1)
答案 10 :(得分:0)
在mac os上你可以调用'open'
import os
os.popen("open myfile.txt")
这将使用TextEdit打开文件,或者将此文件类型设置为默认应用程序
答案 11 :(得分:0)
如果要指定应用程序以在Mac OS X上打开文件,请使用以下命令:
os.system("open -a [app name] [file name]")
答案 12 :(得分:0)
在Windows 8.1上,下面有效,而其他特定方式subprocess.call
失败,路径中有空格。
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))