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

时间:2020-12-29 01:51:24

I need to be able to open a document using its default application in Windows and Mac OS. Basically, I want to do the same thing that happens when you double click on the document icon in Explorer or Finder. What is the best way to do this in Python?

我需要能够使用Windows和Mac OS中的默认应用程序打开文档。基本上,我想做同样的事情,当你双击文档图标在Explorer或Finder中。在Python中,最好的方法是什么?

13 个解决方案

#1


56  

In Mac OS, you can use the "open" command. There is a Windows API call that does something similar, but I don't remember it offhand.

在Mac OS中,可以使用“open”命令。Windows API调用也有类似的功能,但我一时想不起来。

Update

Okay, the "start" command will do it, so this should work.

好的,“开始”命令将会这样做,所以这应该是可行的。

Mac OS/X:

Mac OS / X:

os.system("open "+filename)

Windows:

窗口:

os.system("start "+filename)

Much later update by Edward: os.system works, but it only works with filenames that don't have any spaces in folders and files in the filename (e.g. A:\abc\def\a.txt).

Later Update

Okay, clearly this silly-ass controversy continues, so let's just look at doing this with subprocess.

很明显,这个愚蠢的争论还在继续,让我们来看看用子进程来做这个。

open and start are command interpreter things for Mac OS/X and Windows respectively. Now, let's say we use subprocess. Canonically, you'd use:

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

Now, what are the advantages of this? In theory, this is more secure -- but in fact we're needing to execute a command line one way or the other; in either environment, we need the environment and services to interpet, get paths, and so forth. In neither case are we executing arbitrary text, so it doesn't have an inherent "but you can type 'filename ; rm -rf /'" problem, and IF the file name can be corrupted, using subprocess.call gives us no protection.

这有什么好处呢?在理论上,这更安全——但实际上,我们需要以这样或那样的方式执行命令行;在任何一种环境中,我们都需要环境和服务来进行交互、获取路径等等。在这两种情况下,我们都不会执行任意的文本,所以它没有一个固有的“但是你可以输入‘文件名’;rm -rf /'"问题,如果文件名可能被损坏,使用子进程。电话不能保护我们。

It doesn't actually give us any more error detection, we're still depending on the retcode in either case. We don't need to wait for the child process, since we're by problem statement starting a separate process.

它并没有给我们更多的错误检测,我们仍然依赖于retcode。我们不需要等待子进程,因为我们通过问题语句启动了一个单独的进程。

"But subprocess is preferred." However, os.system() is not deprecated, and it's the simplest tool for this particular job.

“但子流程优先。”然而,os.system()并没有被弃用,它是这个特定作业最简单的工具。

Conclusion: using os.system() is the simplest, most straightforward way to do this, and is therefore a correct answer.

结论:使用os.system()是最简单、最直接的方法,因此是正确的答案。

#2


112  

Use the subprocess module available on Python 2.4+, not os.system(), so you don't have to deal with shell escaping.

使用Python 2.4+上的子进程模块,而不是os.system(),这样您就不必处理shell的转义了。

import subprocess, os
if sys.platform.startswith('darwin'):
    subprocess.call(('open', filepath))
elif os.name == 'nt':
    os.startfile(filepath)
elif os.name == 'posix':
    subprocess.call(('xdg-open', filepath))

The double parentheses are because subprocess.call() wants a sequence as its first argument, so we're using a tuple here. On Linux systems with Gnome there is also a gnome-open command that does the same thing, but xdg-open is the Free Desktop Foundation standard and works across Linux desktop environments.

双括号是因为subprocess.call()想要一个序列作为它的第一个参数,所以我们在这里使用了一个tuple。在使用Gnome的Linux系统上,也有一个Gnome -open命令可以做同样的事情,但是xdga -open是免费的桌面基础标准,可以在Linux桌面环境中工作。

#3


28  

Just for completeness (it wasn't in the question), xdg-open will do the same on Linux.

为了完整性(问题不在这里),xdgopen在Linux上也会这样做。

#4


28  

I prefer:

我喜欢:

os.startfile(path, 'open')

Note that this module supports filenames that have spaces in their folders and files e.g.

注意,这个模块支持文件夹和文件中有空格的文件名,例如。

A:\abc\folder with spaces\file with-spaces.txt

(python docs) 'open' does not have to be added (it is the default). The docs specifically mention that this is like double-clicking on a file's icon in Windows Explorer.

(python文档)“open”不需要添加(它是默认的)。文档特别提到这就像在Windows资源管理器中双击文件的图标。

This solution is windows only.

此解决方案仅适用于windows。

#5


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])

#6


13  

If you have to use an heuristic method, you may consider webbrowser.
It's standard library and despite of its name it would also try to open files:

如果必须使用启发式方法,可以考虑使用webbrowser。它是标准的图书馆,尽管它的名字,它也试图打开文件:

Note that on some platforms, trying to open a filename using this function, may work and start the operating system’s associated program. However, this is neither supported nor portable. (Reference)

注意,在某些平台上,尝试使用此函数打开文件名,可能会工作并启动操作系统的相关程序。然而,这既不支持也不可移植。(参考)

I tried this code and it worked fine in Windows 7 and Ubuntu Natty:

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

import webbrowser
webbrowser.open("path_to_file")

This code also works fine in Windows XP Professional, using Internet Explorer 8.

此代码在使用ie 8的Windows XP专业版中也可以正常工作。

#7


4  

Start does not support long path names and white spaces. You have to convert it to 8.3 compatible paths.

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 )

The file has to exist in order to work with the API call.

为了使用API调用,文件必须存在。

#8


3  

If you want to go the subprocess.call() way, it should look like this on Windows:

如果你想进行子进程。call()方式,它应该在Windows上是这样的:

import subprocess
subprocess.call(('cmd', '/C', 'start', '', FILE_NAME))

You can't just use:

你不能使用:

subprocess.call(('start', FILE_NAME))

because start is not an executable but a command of the cmd.exe program. This works:

因为start不是可执行的,而是cmd的命令。exe程序。如此:

subprocess.call(('cmd', '/C', 'start', FILE_NAME))

but only if there are no spaces in the FILE_NAME.

但前提是FILE_NAME中没有空格。

While subprocess.call method en quotes the parameters properly, the start command has a rather strange syntax, where:

而子流程。调用方法en正确引用参数,start命令的语法相当奇怪,其中:

start notes.txt

does something else than:

别的东西比:

start "notes.txt"

The first quoted string should set the title of the window. To make it work with spaces, we have to do:

第一个引用的字符串应该设置窗口的标题。为了使它与空间一起工作,我们必须:

start "" "my notes.txt"

which is what the code on top does.

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

#9


1  

I am pretty late to the lot, but here is a solution using the windows api. This always opens the associated application.

我来晚了,但是这里有一个使用windows api的解决方案。这总是打开关联的应用程序。

import ctypes

shell32 = ctypes.windll.shell32
file = 'somedocument.doc'

shell32.ShellExecuteA(0,"open",file,0,0,5)

A lot of magic constants. The first zero is the hwnd of the current program. Can be zero. The other two zeros are optional parameters (parameters and directory). 5 == SW_SHOW, it specifies how to execute the app. Read the ShellExecute API docs for more info.

很多神奇的常数。第一个0是当前程序的hwnd。可以是零。另外两个0是可选参数(参数和目录)。5 == SW_SHOW,它指定如何执行应用程序。更多信息请阅读ShellExecute API文档。

#10


1  

os.startfile(path, 'open') under windows is good because when spaces exist in the directory, os.system('start', path_name) can't open the app correct and when the i18n exist in the directory, os.system needs to change the unicode to the codec of the console in Windows.

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

#11


0  

on mac os you can call 'open'

在mac os中,你可以调用'open'

import os
os.popen("open myfile.txt")

this would open the file with TextEdit, or whatever app is set as default for this filetype

这将使用TextEdit打开文件,或者设置为此文件类型的默认应用程序

#12


0  

If you want to specify the app to open the file with on Mac OS X, use this: os.system("open -a [app name] [file name]")

如果您想指定要在Mac OS X上打开文件的应用程序,请使用以下操作系统。系统(“打开-a [app名称][文件名]]”)

#13


0  

On windows 8.1, below have worked while other given ways with subprocess.call fails with path has spaces in it.

在windows8.1中,下面的工作与子流程的其他方法相同。调用失败,路径中有空格。

subprocess.call('cmd /c start "" "any file path with spaces"')

By utilizing this and other's answers before, here's an inline code which works on multiple platforms.

通过利用这个和其他之前的答案,这里有一个在多个平台上工作的内联代码。

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))

#1


56  

In Mac OS, you can use the "open" command. There is a Windows API call that does something similar, but I don't remember it offhand.

在Mac OS中,可以使用“open”命令。Windows API调用也有类似的功能,但我一时想不起来。

Update

Okay, the "start" command will do it, so this should work.

好的,“开始”命令将会这样做,所以这应该是可行的。

Mac OS/X:

Mac OS / X:

os.system("open "+filename)

Windows:

窗口:

os.system("start "+filename)

Much later update by Edward: os.system works, but it only works with filenames that don't have any spaces in folders and files in the filename (e.g. A:\abc\def\a.txt).

Later Update

Okay, clearly this silly-ass controversy continues, so let's just look at doing this with subprocess.

很明显,这个愚蠢的争论还在继续,让我们来看看用子进程来做这个。

open and start are command interpreter things for Mac OS/X and Windows respectively. Now, let's say we use subprocess. Canonically, you'd use:

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

Now, what are the advantages of this? In theory, this is more secure -- but in fact we're needing to execute a command line one way or the other; in either environment, we need the environment and services to interpet, get paths, and so forth. In neither case are we executing arbitrary text, so it doesn't have an inherent "but you can type 'filename ; rm -rf /'" problem, and IF the file name can be corrupted, using subprocess.call gives us no protection.

这有什么好处呢?在理论上,这更安全——但实际上,我们需要以这样或那样的方式执行命令行;在任何一种环境中,我们都需要环境和服务来进行交互、获取路径等等。在这两种情况下,我们都不会执行任意的文本,所以它没有一个固有的“但是你可以输入‘文件名’;rm -rf /'"问题,如果文件名可能被损坏,使用子进程。电话不能保护我们。

It doesn't actually give us any more error detection, we're still depending on the retcode in either case. We don't need to wait for the child process, since we're by problem statement starting a separate process.

它并没有给我们更多的错误检测,我们仍然依赖于retcode。我们不需要等待子进程,因为我们通过问题语句启动了一个单独的进程。

"But subprocess is preferred." However, os.system() is not deprecated, and it's the simplest tool for this particular job.

“但子流程优先。”然而,os.system()并没有被弃用,它是这个特定作业最简单的工具。

Conclusion: using os.system() is the simplest, most straightforward way to do this, and is therefore a correct answer.

结论:使用os.system()是最简单、最直接的方法,因此是正确的答案。

#2


112  

Use the subprocess module available on Python 2.4+, not os.system(), so you don't have to deal with shell escaping.

使用Python 2.4+上的子进程模块,而不是os.system(),这样您就不必处理shell的转义了。

import subprocess, os
if sys.platform.startswith('darwin'):
    subprocess.call(('open', filepath))
elif os.name == 'nt':
    os.startfile(filepath)
elif os.name == 'posix':
    subprocess.call(('xdg-open', filepath))

The double parentheses are because subprocess.call() wants a sequence as its first argument, so we're using a tuple here. On Linux systems with Gnome there is also a gnome-open command that does the same thing, but xdg-open is the Free Desktop Foundation standard and works across Linux desktop environments.

双括号是因为subprocess.call()想要一个序列作为它的第一个参数,所以我们在这里使用了一个tuple。在使用Gnome的Linux系统上,也有一个Gnome -open命令可以做同样的事情,但是xdga -open是免费的桌面基础标准,可以在Linux桌面环境中工作。

#3


28  

Just for completeness (it wasn't in the question), xdg-open will do the same on Linux.

为了完整性(问题不在这里),xdgopen在Linux上也会这样做。

#4


28  

I prefer:

我喜欢:

os.startfile(path, 'open')

Note that this module supports filenames that have spaces in their folders and files e.g.

注意,这个模块支持文件夹和文件中有空格的文件名,例如。

A:\abc\folder with spaces\file with-spaces.txt

(python docs) 'open' does not have to be added (it is the default). The docs specifically mention that this is like double-clicking on a file's icon in Windows Explorer.

(python文档)“open”不需要添加(它是默认的)。文档特别提到这就像在Windows资源管理器中双击文件的图标。

This solution is windows only.

此解决方案仅适用于windows。

#5


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])

#6


13  

If you have to use an heuristic method, you may consider webbrowser.
It's standard library and despite of its name it would also try to open files:

如果必须使用启发式方法,可以考虑使用webbrowser。它是标准的图书馆,尽管它的名字,它也试图打开文件:

Note that on some platforms, trying to open a filename using this function, may work and start the operating system’s associated program. However, this is neither supported nor portable. (Reference)

注意,在某些平台上,尝试使用此函数打开文件名,可能会工作并启动操作系统的相关程序。然而,这既不支持也不可移植。(参考)

I tried this code and it worked fine in Windows 7 and Ubuntu Natty:

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

import webbrowser
webbrowser.open("path_to_file")

This code also works fine in Windows XP Professional, using Internet Explorer 8.

此代码在使用ie 8的Windows XP专业版中也可以正常工作。

#7


4  

Start does not support long path names and white spaces. You have to convert it to 8.3 compatible paths.

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 )

The file has to exist in order to work with the API call.

为了使用API调用,文件必须存在。

#8


3  

If you want to go the subprocess.call() way, it should look like this on Windows:

如果你想进行子进程。call()方式,它应该在Windows上是这样的:

import subprocess
subprocess.call(('cmd', '/C', 'start', '', FILE_NAME))

You can't just use:

你不能使用:

subprocess.call(('start', FILE_NAME))

because start is not an executable but a command of the cmd.exe program. This works:

因为start不是可执行的,而是cmd的命令。exe程序。如此:

subprocess.call(('cmd', '/C', 'start', FILE_NAME))

but only if there are no spaces in the FILE_NAME.

但前提是FILE_NAME中没有空格。

While subprocess.call method en quotes the parameters properly, the start command has a rather strange syntax, where:

而子流程。调用方法en正确引用参数,start命令的语法相当奇怪,其中:

start notes.txt

does something else than:

别的东西比:

start "notes.txt"

The first quoted string should set the title of the window. To make it work with spaces, we have to do:

第一个引用的字符串应该设置窗口的标题。为了使它与空间一起工作,我们必须:

start "" "my notes.txt"

which is what the code on top does.

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

#9


1  

I am pretty late to the lot, but here is a solution using the windows api. This always opens the associated application.

我来晚了,但是这里有一个使用windows api的解决方案。这总是打开关联的应用程序。

import ctypes

shell32 = ctypes.windll.shell32
file = 'somedocument.doc'

shell32.ShellExecuteA(0,"open",file,0,0,5)

A lot of magic constants. The first zero is the hwnd of the current program. Can be zero. The other two zeros are optional parameters (parameters and directory). 5 == SW_SHOW, it specifies how to execute the app. Read the ShellExecute API docs for more info.

很多神奇的常数。第一个0是当前程序的hwnd。可以是零。另外两个0是可选参数(参数和目录)。5 == SW_SHOW,它指定如何执行应用程序。更多信息请阅读ShellExecute API文档。

#10


1  

os.startfile(path, 'open') under windows is good because when spaces exist in the directory, os.system('start', path_name) can't open the app correct and when the i18n exist in the directory, os.system needs to change the unicode to the codec of the console in Windows.

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

#11


0  

on mac os you can call 'open'

在mac os中,你可以调用'open'

import os
os.popen("open myfile.txt")

this would open the file with TextEdit, or whatever app is set as default for this filetype

这将使用TextEdit打开文件,或者设置为此文件类型的默认应用程序

#12


0  

If you want to specify the app to open the file with on Mac OS X, use this: os.system("open -a [app name] [file name]")

如果您想指定要在Mac OS X上打开文件的应用程序,请使用以下操作系统。系统(“打开-a [app名称][文件名]]”)

#13


0  

On windows 8.1, below have worked while other given ways with subprocess.call fails with path has spaces in it.

在windows8.1中,下面的工作与子流程的其他方法相同。调用失败,路径中有空格。

subprocess.call('cmd /c start "" "any file path with spaces"')

By utilizing this and other's answers before, here's an inline code which works on multiple platforms.

通过利用这个和其他之前的答案,这里有一个在多个平台上工作的内联代码。

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))