Belgeyi hem Windows hem de Mac OS'de Python'da varsayılan işletim sistemi uygulamasıyla açın


126

Windows ve Mac OS'de varsayılan uygulamasını kullanarak bir belgeyi açabilmem gerekiyor. Temel olarak, Explorer veya Finder'da belge simgesine çift tıkladığınızda olanla aynı şeyi yapmak istiyorum. Bunu Python'da yapmanın en iyi yolu nedir?


9
Bunun 2008'den itibaren Python izleyicisindeki standart kitaplığa dahil edilmesi için bir sorun var: bugs.python.org/issue3177
Ram Rachum

Yanıtlar:


77

openve startbunu yapmak için sırasıyla Mac OS / X ve Windows için komut yorumlayıcı şeylerdir.

Bunları Python'dan çağırmak için subprocessmodül veya os.system().

İşte hangi paketin kullanılacağıyla ilgili dikkat edilmesi gereken noktalar:

  1. Onları şu şekilde arayabilirsin os.system, ama ...

    Kaçış: os.system yalnızca yol adında boşluk veya başka kabuk meta karakterleri olmayan dosya adlarıyla çalışır (örn. A:\abc\def\a.txt), Aksi takdirde bunların öncelenmesi gerekir. Orada shlex.quoteUnix benzeri sistemler için, ancak Windows için hiçbir şey gerçekten standardı. Belki ayrıca python, windows: shlex ile komut satırlarını ayrıştırma

    • Mac OS X: os.system("open " + shlex.quote(filename))
    • Windows: os.system("start " + filename)düzgün konuşmanın filenameda kaçması gereken yer.
  2. Bunları subprocessmodül aracılığıyla da arayabilirsiniz , ancak ...

    Python 2.7 ve daha yenisi için şunu kullanın:

    subprocess.check_call(['open', filename])

    Python 3.5+ ile biraz daha karmaşık ama aynı zamanda biraz daha çok yönlü olanı eşit olarak kullanabilirsiniz.

    subprocess.run(['open', filename], check=True)

    Python 2.4'e kadar tamamen uyumlu olmanız gerekiyorsa subprocess.call(), kendi hata kontrolünüzü kullanabilir ve uygulayabilirsiniz:

    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
    

    Şimdi kullanmanın avantajları subprocessnelerdir?

    • Güvenlik: Teorik olarak, bu daha güvenlidir, ama aslında bir komut satırını şu ya da bu şekilde yürütmemiz gerekiyor; her iki ortamda da yorumlamak, yollar bulmak vb. için çevre ve hizmetlere ihtiyacımız var. Her iki durumda da biz bu yüzden doğal bir yok "ama sen yazabilirsiniz, keyfi metin yürütme vardır 'filename ; rm -rf /'" sorunu ve eğer dosya adı bozuk olabilir, kullanarak subprocess.callbize biraz ek koruma sağlar.
    • Hata işleme: Aslında bize daha fazla hata tespiti sağlamaz, biz hala retcodeher iki durumda da bağlıyız; ancak bir hata durumunda açıkça bir istisna oluşturma davranışı, bir hata olup olmadığını fark etmenize kesinlikle yardımcı olacaktır (ancak bazı senaryolarda, bir geri bildirim, hatayı göz ardı etmekten daha fazla yardımcı olmayabilir).
    • Bir (engellemeyen) alt süreç ortaya çıkarır : Alt süreci beklememize gerek yoktur, çünkü ayrı bir süreç başlatan sorun bildirimi.

    İtiraza "Ama subprocesstercih edilir." Ancak, os.system()kullanımdan kaldırılmamıştır ve bir bakıma bu belirli iş için en basit araçtır. Sonuç: os.system()bu nedenle kullanmak da doğru bir cevaptır.

    Belirgin bir dezavantaj , Windows startkomutunun , kullanmanın yararlarının çoğunu geçersiz kılan geçiş yapmanızı gerektirmesidir .shell=Truesubprocess


2
filenameFormun nereden geldiğine bağlı olarak bu, os.system () işlevinin neden güvensiz ve kötü olduğuna dair mükemmel bir örnektir. alt işlem daha iyidir.
Devin Jeanpierre

6
Nick'in cevabı bana güzel görünüyordu. Yolumuza hiçbir şey çıkmadı. Bir şeyleri yanlış örnekler kullanarak açıklamak kolay kolay gerekçelendirilemez.
Devin Jeanpierre

2
Alt işlem kullanmaktan daha az güvenli ve daha az esnektir. Bu bana yanlış geliyor.
Devin Jeanpierre

8
Tabii ki önemli. İyi bir cevap ile kötü bir cevap (veya korkunç bir cevap) arasındaki farktır. Os.system () için dokümanlar "Alt işlem modülünü kullan" der. Daha ne gerekiyor? Bu benim için yeterince küçümseme.
Devin Jeanpierre

20
Bu tartışmayı yeniden başlatmak konusunda biraz isteksiz hissediyorum, ancak "Daha sonra güncelleme" bölümünün tamamen yanlış anladığını düşünüyorum. Buradaki sorun os.system(), kabuğu kullanmasıdır (ve burada herhangi bir kabuk kaçışı yapmıyorsunuz, bu nedenle Kabuk meta karakterleri içeren mükemmel şekilde geçerli dosya adları için Bad Things gerçekleşecek). subprocess.call()Tercih edilmesinin nedeni , kullanarak kabuğu atlatma seçeneğinizin olmasıdır subprocess.call(["open", filename]). Bu, tüm geçerli dosya adları için çalışır ve güvenilmeyen dosya adları için bile bir kabuk enjeksiyon güvenlik açığı oluşturmaz.
Sven Marnach

151

subprocessPython 2.4+ üzerinde bulunan modülü kullanın os.system(), bu yüzden kabuk kaçışıyla uğraşmak zorunda kalmazsınız.

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

Çift parantezler subprocess.call(), ilk argüman olarak bir dizi istediği için, bu yüzden burada bir demet kullanıyoruz. Gnome ile Linux sistemlerinde gnome-openaynı şeyi yapan bir komut da vardır , ancak xdg-openFree Desktop Foundation standardıdır ve Linux masaüstü ortamlarında çalışır.


5
Subprocess.call () 'da' start 'kullanmak Windows'ta çalışmaz - start gerçekten bir yürütülebilir dosya değildir.
Tomas Sedovic

4
nitpick: tüm linuxen'de (ve sanırım çoğu BSD'de) kullanmanız gereken xdg-open- linux.die.net/man/1/xdg-open
gnud

6
Windows'ta start bir kabuk komutudur, yürütülebilir değildir. Subprocess.call (('start', filepath), shell = True) kullanabilirsiniz, ancak bir kabukta çalıştırıyorsanız os.system'i de kullanabilirsiniz.
Peter Graham

Koştum xdg-open test.pyve benim için firefox indirme iletişim kutusunu açtı. Sorun nedir? Manjaro linux kullanıyorum.
Jason

1
@Jason xdg-openYapılandırmanızın kafası karışmış gibi görünüyor , ancak bu gerçekten bir yorumda giderebileceğimiz bir şey değil. Belki bkz. Unix.stackexchange.com/questions/36380/…
tripleee

44

Tercih ederim:

os.startfile(path, 'open')

Bu modülün, klasörlerinde ve dosyalarında boşluklar olan dosya adlarını desteklediğini unutmayın.

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

( python docs ) 'open' eklenmek zorunda değildir (bu varsayılandır). Dokümanlar özellikle bunun Windows Gezgini'nde bir dosya simgesine çift tıklamaya benzediğini belirtiyor.

Bu çözüm yalnızca pencerelerdir.


Teşekkürler. Dokümanlar son paragrafa eklendiği için kullanılabilirliği fark etmedim. Diğer çoğu bölümde, kullanılabilirlik notu kendi satırında yer alır.
DrBloodmoney

Linux'ta bazı nedenlerden dolayı, bir hatayı yükseltmek yerine, startfileişlev mevcut değildir, bu da kullanıcıların eksik bir işlevle ilgili kafa karıştırıcı bir hata mesajı alacağı anlamına gelir. Bundan kaçınmak için platformu kontrol etmek isteyebilirsiniz.
cz

39

Sırf bütünlük için (söz konusu değildi), xdg-open aynı şeyi Linux'ta yapacak.


6
+1 Genellikle, yanıt verenler sorulmayan soruları yanıtlamamalıdır, ancak bu durumda SO topluluğu için çok alakalı ve yararlı olduğunu düşünüyorum.
demongolem

bunu arıyordu
nurettin

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
Huh, başlangıç ​​dosyası hakkında bir şey bilmiyordum. Python'un Mac ve Linux sürümleri benzer anlambilim alsaydı güzel olurdu.
Nick

3
İlgili python hatası: bugs.python.org/issue3177 - güzel bir yama sağlayın ve kabul edilebilir =)
gnud

linux için xdg-open komutu
TheTechRobo36414519

21

Sezgisel bir yöntem kullanmanız gerekiyorsa, düşünebilirsiniz webbrowser.
Standart kitaplıktır ve adına rağmen dosyaları açmaya çalışır:

Bazı platformlarda, bu işlevi kullanarak bir dosya adını açmaya çalışmanın, çalışabileceğini ve işletim sisteminin ilişkili programını başlatabileceğini unutmayın. Ancak bu ne desteklenmekte ne de taşınabilir. ( Referans )

Bu kodu denedim ve Windows 7 ve Ubuntu Natty'de iyi çalıştı:

import webbrowser
webbrowser.open("path_to_file")

Bu kod, Internet Explorer 8 kullanılarak Windows XP Professional'da da sorunsuz çalışır.


3
Anladığım kadarıyla, bu açık arayla en iyi cevap. Çapraz platform gibi görünüyor ve hangi platformun kullanımda olduğunu kontrol etmeye veya işletim sistemini, platformu içe aktarmaya gerek yok.
2013

2
@jonathanrocher: Kaynak kodda Mac desteğini görüyorum . open locationYolu geçerli bir url olarak verirseniz çalışması gereken orada kullanır .
jfs

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 "Bazı platformlarda, [webbrowser.open (url)] kullanarak bir dosya adını açmaya çalışmanın çalışabileceğini ve işletim sisteminin ilişkili programını başlatabileceğini unutmayın. , bu ne desteklenmekte ne de taşınabilir. "
nyanpasu64

6

Yolunuza gitmek istiyorsanız subprocess.call(), Windows'ta şöyle görünmelidir:

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

Sadece kullanamazsınız:

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

çünkü start çalıştırılabilir değil, cmd.exeprogramın bir komutu . Bu çalışıyor:

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

ancak yalnızca FILE_NAME dosyasında boşluk yoksa.

İken subprocess.callyöntem tr parametreleri düzgün tırnak, startkomut oldukça garip bir sözdizimi vardır:

start notes.txt

şunlardan başka bir şey yapar:

start "notes.txt"

İlk alıntılanan dize, pencerenin başlığını belirlemelidir. Alanlarla çalışmasını sağlamak için şunları yapmalıyız:

start "" "my notes.txt"

üstteki kodun yaptığı da budur.


5

Başlangıç, uzun yol adlarını ve beyaz boşlukları desteklemez. 8.3 uyumlu yollara dönüştürmelisiniz.

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 çağrısıyla çalışabilmesi için dosyanın var olması gerekir.


1
Başka bir geçici çözüm, ona tırnak içinde bir başlık vermektir, örneğinstart "Title" "C:\long path to\file.avi"
user3364825

3

Çok geç kaldım ama işte windows api kullanarak bir çözüm. Bu her zaman ilişkili uygulamayı açar.

import ctypes

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

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

Bir sürü sihirli sabit. İlk sıfır, mevcut programın hwnd'sidir. Sıfır olabilir. Diğer iki sıfır isteğe bağlı parametrelerdir (parametreler ve dizin). 5 == SW_SHOW, uygulamanın nasıl çalıştırılacağını belirtir. Daha fazla bilgi için ShellExecute API belgelerini okuyun .


1
nasıl karşılaştırılır os.startfile(file)?
jfs

2

mac os'ta 'açık' diyebilirsiniz

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

bu, dosyayı TextEdit ile açar veya bu dosya türü için varsayılan olarak hangi uygulama ayarlanmışsa açılır


2

Dosyayı Mac OS X'te açacağınız uygulamayı belirtmek istiyorsanız, şunu kullanın: os.system("open -a [app name] [file name]")


2

Windows 8.1'de, yol ile subprocess.callbaşarısız olan diğer verilen yollar içinde boşluklar varken, aşağıda çalıştı .

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

Bunu ve diğerlerinin yanıtlarını daha önce kullanarak, işte birden çok platformda çalışan bir satır içi kod.

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 altında iyidir çünkü dizinde boşluklar olduğunda os.system('start', path_name), uygulamayı doğru bir şekilde açamaz ve i18n dizinde bulunduğunda, os.systemunicode'u Windows'ta konsolun codec'ine değiştirmesi gerekir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.