Je dois pouvoir ouvrir un document avec son application par défaut sous Windows et Mac OS. En gros, je veux faire la même chose que lorsque vous double-cliquez sur l'icône du document dans l'Explorateur ou le Finder. Quelle est la meilleure façon de faire cela en Python?
open
et start
sont des interpréteurs de commandes pour Mac OS/X et Windows, respectivement, pour ce faire.
Pour les appeler à partir de Python, vous pouvez utiliser subprocess
module ou os.system()
.
Voici les considérations sur le paquet à utiliser:
Vous pouvez les appeler via os.system
, Qui fonctionne, mais ...
Échappement: os.system
Ne fonctionne qu'avec les noms de fichiers ne comportant aucun espace ni autre métacaractère Shell dans le chemin (par exemple, A:\abc\def\a.txt
), ou alors il faut y échapper. Il y a shlex.quote
Pour les systèmes de type Unix, mais rien de vraiment standard pour Windows. Peut-être aussi voir python, windows: analyse des lignes de commande avec shlex
os.system("open " + shlex.quote(filename))
os.system("start " + filename)
où proprement dit filename
devrait également être échappé.Vous pouvez aussi les appeler via le module subprocess
, mais ...
Pour Python 2.7 et plus récent, utilisez simplement
subprocess.check_call(['open', filename])
Dans Python 3.5+, vous pouvez également utiliser le légèrement plus complexe mais aussi un peu plus polyvalent
subprocess.run(['open', filename], check=True)
Si vous devez être compatible jusqu’à Python 2.4, vous pouvez utiliser subprocess.call()
] et implémenter votre propre vérification des erreurs:
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
Maintenant, quels sont les avantages d’utiliser subprocess
?
'filename ; rm -rf /'
" Et if le nom du fichier peut être corrompu, l’utilisation de subprocess.call
ne nous donne que peu de protection supplémentaire.retcode
dans les deux cas; mais le fait de lever explicitement une exception en cas d'erreur vous aidera certainement à le signaler en cas d'échec (bien que, dans certains cas, une analyse rétrospective pourrait ne pas être plus utile que de simplement ignorer l'erreur).A l'objection "Mais subprocess
est préféré." Cependant, os.system()
n'est pas obsolète, et constitue en quelque sorte l'outil le plus simple pour ce travail particulier. Conclusion: utiliser os.system()
est donc aussi une réponse correcte.
Un inconvénient marqué est que Windows start
commande requiert vous devez passer Shell=True
qui annule la plupart des avantages de l'utilisation de subprocess
.
Utilisez le module subprocess
disponible sur Python 2.4+, et non os.system()
] _, afin que vous n'ayez pas à gérer l'échappement de 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))
Les doubles parenthèses sont dues au fait que subprocess.call()
veut une séquence comme premier argument, nous utilisons donc un Tuple ici. Sur les systèmes Linux avec Gnome, il existe également une commande gnome-open
Qui fait la même chose, mais xdg-open
Est la norme Free Desktop Foundation et fonctionne sur les environnements de bureau Linux.
Je préfère:
os.startfile(path, 'open')
Notez que ce module prend en charge les noms de fichiers contenant des espaces dans leurs dossiers et leurs fichiers, par exemple.
A:\abc\folder with spaces\file with-spaces.txt
( python docs ) 'open' n'a pas besoin d'être ajouté (c'est la valeur par défaut). Les documents mentionnent spécifiquement qu'il s'agit d'un double-clic sur l'icône d'un fichier dans l'Explorateur Windows.
Cette solution est uniquement sous Windows.
Juste pour être complet (ce n’était pas dans la question), xdg-open fera de même sous Linux.
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])
Si vous devez utiliser une méthode heuristique, vous pouvez considérer webbrowser
.
C'est une bibliothèque standard et malgré son nom, elle essaierait également d'ouvrir des fichiers:
Notez que sur certaines plates-formes, essayer d’ouvrir un nom de fichier en utilisant cette fonction peut fonctionner et démarrer le programme associé au système d’exploitation. Cependant, ceci n'est ni supporté ni portable. ( référence )
J'ai essayé ce code et cela a bien fonctionné sous Windows 7 et Ubuntu Natty:
import webbrowser
webbrowser.open("path_to_file")
Ce code fonctionne également très bien sous Windows XP Professional, avec Internet Explorer 8.
Démarrer ne prend pas en charge les noms de chemin longs et les espaces. Vous devez le convertir en chemins compatibles 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 )
Le fichier doit exister pour pouvoir fonctionner avec l'appel de l'API.
Si vous voulez utiliser la méthode subprocess.call()
, cela devrait ressembler à ceci sous Windows:
import subprocess
subprocess.call(('cmd', '/C', 'start', '', FILE_NAME))
Vous ne pouvez pas simplement utiliser:
subprocess.call(('start', FILE_NAME))
parce que start
n’est pas un exécutable mais une commande du cmd.exe
programme. Cela marche:
subprocess.call(('cmd', '/C', 'start', FILE_NAME))
mais seulement s'il n'y a pas d'espaces dans FILE_NAME.
Tandis que subprocess.call
méthode encite les paramètres correctement, la commande start
a une syntaxe plutôt étrange, où:
start notes.txt
fait autre chose que:
start "notes.txt"
La première chaîne entre guillemets doit définir le titre de la fenêtre. Pour que cela fonctionne avec des espaces, nous devons faire:
start "" "my notes.txt"
c'est ce que fait le code en haut.
Je suis assez tard pour le lot, mais voici une solution utilisant l’API Windows. Cela ouvre toujours l'application associée.
import ctypes
Shell32 = ctypes.windll.Shell32
file = 'somedocument.doc'
Shell32.ShellExecuteA(0,"open",file,0,0,5)
Beaucoup de constantes magiques. Le premier zéro est le hwnd du programme en cours. Peut être zéro. Les deux autres zéros sont des paramètres facultatifs (paramètres et répertoire). 5 == SW_SHOW, il spécifie comment exécuter l'application. Lisez le docs de l'API ShellExecute pour plus d'informations.
os.startfile (chemin, 'ouvrir') sous Windows est bon car, lorsqu'il existe des espaces dans le répertoire, os.system ('start', nom_du_ chemin) ne peut pas ouvrir l'application correctement et lorsque l'i18n existe dans le répertoire, os. Le système doit remplacer le code unicode par le codec de la console sous Windows.
Sur les fenêtres 8.1, ci-dessous ont fonctionné alors que d’autres manières données avec subprocess.call
échoue avec chemin contenant des espaces.
subprocess.call('cmd /c start "" "any file path with spaces"')
En utilisant ceci et les réponses d'autres avant, voici un code en ligne qui fonctionne sur plusieurs plates-formes.
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))
Si vous souhaitez spécifier l'application avec laquelle ouvrir le fichier sous Mac OS X, utilisez ceci: os.system("open -a [app name] [file name]")
sur mac os vous pouvez appeler 'open'
import os
os.popen("open myfile.txt")
cela ouvrirait le fichier avec TextEdit, ou quelle que soit l'application définie par défaut pour ce type de fichier