WindowsとMac OSの両方で、PythonのデフォルトのOSアプリケーションでドキュメントを開く


125

WindowsとMac OSでデフォルトのアプリケーションを使用してドキュメントを開くことができる必要があります。基本的には、エクスプローラーやファインダーでドキュメントのアイコンをダブルクリックしたときと同じことをしたいと思います。Pythonでこれを行う最良の方法は何ですか?


9
これが2008年からPythonトラッカーの標準ライブラリに含まれるという問題がありました:bugs.python.org/issue3177
Ram Rachum

回答:


77

openこれstartは、Mac OS / XとWindows用のコマンドインタープリターです。

それらをPythonから呼び出すには、subprocessモジュールまたはを使用できますos.system()

使用するパッケージに関する考慮事項は次のとおりです。

  1. 経由os.systemで呼び出すことができますが、機能しますが...

    エスケープ: os.systemパス名にスペースやその他のシェルメタ文字が含まれていないファイル名でのみ機能します(例:)、A:\abc\def\a.txtそうでない場合はエスケープする必要があります。shlex.quoteUnixライクなシステムにはありますが、Windowsには標準的なものはありません。多分python、windowsも参照してください:shlexでコマンドラインを解析する

    • MacOS / X: os.system("open " + shlex.quote(filename))
    • Windows:os.system("start " + filename)適切に話すfilenameことも回避する必要がある場合。
  2. 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 /'」という問題はありません。ファイル名が破損する可能性がある場合は、使用しsubprocess.callても追加の保護はほとんどありません。
    • エラー処理:実際にはそれ以上のエラー検出は行われませんretcode。どちらの場合も依然として依存しています。ただし、エラーが発生した場合に明示的に例外を発生させる動作は、エラーが発生したかどうかを確認するのに役立ちます(一部のシナリオでは、トレースバックは単にエラーを無視するよりも役に立たない場合があります)。
    • (非ブロッキング)サブプロセスを生成します。問題ステートメントによって別のプロセスを開始しているため、子プロセスを待つ必要はありません。

    「しかしsubprocess、望ましい」という反対意見に。ただし、os.system()は非推奨ではなく、ある意味で、この特定のジョブのための最も簡単なツールです。結論:os.system()したがって、使用も正解です。

    マーク欠点は、Windowsのことであるstartコマンドが必要として渡すことができshell=True使用することの利点のほとんどを否定していますsubprocess


2
どこにfilename来るかによって、これはos.system()が安全でなく、悪い理由の完璧な例です。サブプロセスが優れています。
Devin Jeanpierre

6
ニックの答えは私にはうまく見えた。何も邪魔になりません。間違った例を使って説明するのは簡単ではありません。
Devin Jeanpierre

2
サブプロセスを使用するよりも安全性と柔軟性が低くなります。それは私には間違っているようです。
Devin Jeanpierre

8
もちろんそれは重要です。それは良い答えと悪い答え(またはひどい答え)の違いです。os.system()自体のドキュメントには、「サブプロセスモジュールを使用する」と書かれています。さらに何が必要ですか?私にとってはそれで十分です。
Devin Jeanpierre

20
この議論を再開するのには少し気が進まないのですが、「後の更新」セクションでは完全に間違っています。の問題os.system()は、シェルを使用することです(ここではシェルエスケープを実行していないため、シェルのメタ文字が含まれている完全に有効なファイル名で問題が発生します)。subprocess.call()推奨される理由は、を使用してシェルをバイパスするオプションがあるためsubprocess.call(["open", filename])です。これはすべての有効なファイル名で機能し、信頼できないファイル名であっても、シェル注入の脆弱性をもたらすことはありません。
スヴェンMarnach

150

使用subprocessのPython 2.4+で利用可能なモジュールを、ないos.system()、あなたはシェルエスケープに対処する必要はありませんので。

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デスクトップ環境全体で機能します。


5
subprocess.call()で 'start'を使用してもWindowsでは機能しません-startは実際には実行可能ではありません。
Tomas Sedovic

4
nitpick:すべてlinuxen上の(と私はほとんどのBSDを推測)あなたが使用する必要がありますxdg-open- linux.die.net/man/1/xdg-open
gnud

6
Windowsでの起動はシェルコマンドであり、実行可能ファイルではありません。subprocess.call(( 'start'、filepath)、shell = True)を使用できますが、シェルで実行している場合はos.systemも使用できます。
Peter Graham、

実行するxdg-open test.pyと、Firefoxのダウンロードダイアログが開きました。どうしましたか?私はmanjaro linuxを使っています。
ジェイソン

1
@ジェイソンあなたのxdg-open構成が混乱しているように聞こえますが、それはコメントでトラブルシューティングできるものではありません。unix.stackexchange.com/questions/36380/…を
tripleee

44

私は好む:

os.startfile(path, 'open')

このモジュールは、フォルダとファイルにスペースがあるファイル名をサポートしていることに注意してください。

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

python docs) 'open'を追加する必要はありません(デフォルトです)。ドキュメントでは、これはWindowsエクスプローラーでファイルのアイコンをダブルクリックするようなものであると具体的に述べています。

このソリューションはWindowsのみです。


ありがとう。ドキュメントの最後の段落に追加されているので、私は可用性に気づきませんでした。他のほとんどのセクションでは、利用可能メモが独自の行を占めています。
DrBloodmoney 2009年

Linuxでは、なんらかの理由でエラーが発生startfileするのではなく、関数が存在しません。つまり、関数が見つからないという混乱したエラーメッセージが表示されます。これを回避するためにプラットフォームを確認することをお勧めします。
CZ

39

完全を期すために(問題ではありませんでした)、xdg-openはLinuxでも同じことを行います。


6
+1通常、レスポンダは質問されなかった質問には答えるべきではありませんが、この場合、それはSOコミュニティ全体にとって非常に関連性があり、役立つと思います。
デーモンゴレム

これを探していました
ヌレティン

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

2
ああ、startfileについては知りませんでした。MacとLinuxのバージョンのPythonが同様のセマンティクスを採用しているといいですね。
ニック

3
関連するpythonのバグ:bugs.python.org/issue3177-素敵なパッチを提供してください、そしてそれは受け入れられるかもしれません=)
gnud

Linux用のxdg-openコマンド
TheTechRobo36414519

21

ヒューリスティックな方法を使用する必要がある場合は、を検討してくださいwebbrowser
これは標準ライブラリであり、その名前にもかかわらず、ファイルを開こうとします。

一部のプラットフォームでは、この関数を使用してファイル名を開こうとすると、動作し、オペレーティングシステムの関連プログラムが起動する場合があります。ただし、これはサポートされておらず、移植性もありません。(参考

私はこのコードを試してみましたが、Windows 7とUbuntu Nattyでは問題なく動作しました。

import webbrowser
webbrowser.open("path_to_file")

このコードは、Internet Explorer 8を使用するWindows XP Professionalでも正常に機能します。


3
私の知る限り、これが断然最良の答えです。クロスプラットフォームのようで、使用中のプラットフォームをチェックしたり、OS、プラットフォームをインポートしたりする必要はありません。
ポーランド人2013年

2
@jonathanrocher:私はソースコードでMacのサポートを見ています。それは使用していますopen locationあなたが有効なURLとしてパスを与えればそれが動作するはずですが。
jfs 2015

1
macOS:import webbrowser webbrowser.open("file:///Users/nameGoesHere/Desktop/folder/file.py")
Daniel Springer

3
docs.python.org/3/library/webbrowser.html#webbrowser.open「一部のプラットフォームでは、[webbrowser.open(url)]を使用してファイル名を開こうとすると、オペレーティングシステムの関連プログラムが動作し、起動する場合があります。ただし、 、これはサポートされておらず、移植性もありません。」
nyanpasu64

6

先に進む場合はsubprocess.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))

ただし、FILE_NAMEにスペースがない場合のみ。

一方でsubprocess.callメソッドエンパラメータ適切に引用符は、startコマンドではなく奇妙な構文を持っています:

start notes.txt

以外のことをします:

start "notes.txt"

最初に引用された文字列は、ウィンドウのタイトルを設定する必要があります。スペースで機能させるには、次のことを行う必要があります。

start "" "my notes.txt"

これが一番上のコードが行うことです。


5

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呼び出しを処理するには、ファイルが存在している必要があります。


1
別の回避策は、引用符でタイトルを付けることです。たとえば、start "Title" "C:\long path to\file.avi"
user3364825

3

私はかなり遅くなっていますが、これはWindows APIを使用したソリューションです。これにより、常に関連するアプリケーションが開きます。

import ctypes

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

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

たくさんの魔法の定数。最初のゼロは現在のプログラムのhwndです。ゼロにすることができます。他の2つのゼロはオプションのパラメーター(パラメーターとディレクトリー)です。5 == SW_SHOW、アプリの実行方法を指定します。詳細については、 ShellExecute APIドキュメントをご覧ください。


1
それはどのように比較しos.startfile(file)ますか?
jfs

2

Mac OSでは「オープン」と呼ぶことができます

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

これは、TextEdit、またはこのファイルタイプのデフォルトとして設定されているアプリでファイルを開きます


2

Mac OS Xでファイルを開くアプリを指定する場合は、次のようにします。 os.system("open -a [app name] [file name]")


2

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

2

os.startfile(path, 'open')Windowsでは、ディレクトリにスペースが存在する場合os.system('start', path_name)、アプリを正しく開くことができず、i18nがディレクトリに存在する場合os.system、UnicodeをWindowsのコンソールのコーデックに変更する必要があるため、Windowsでは問題ありません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.