Open document with default OS application in Python, both in Windows and Mac OS

前端 未结 13 1315
刺人心
刺人心 2020-11-22 10:36

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 do

相关标签:
13条回答
  • 2020-11-22 10:58

    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 correctly and when the i18n exist in the directory, os.system needs to change the unicode to the codec of the console in Windows.

    0 讨论(0)
  • 2020-11-22 10:59

    open and start are command-interpreter things for Mac OS/X and Windows respectively, to do this.

    To call them from Python, you can either use subprocess module or os.system().

    Here are considerations on which package to use:

    1. You can call them via os.system, which works, but...

      Escaping: os.system only works with filenames that don't have any spaces or other shell metacharacters in the pathname (e.g. A:\abc\def\a.txt), or else these need to be escaped. There is shlex.quote for Unix-like systems, but nothing really standard for Windows. Maybe see also python, windows : parsing command lines with shlex

      • MacOS/X: os.system("open " + shlex.quote(filename))
      • Windows: os.system("start " + filename) where properly speaking filename should be escaped, too.
    2. You can also call them via subprocess module, but...

      For Python 2.7 and newer, simply use

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

      In Python 3.5+ you can equivalently use the slightly more complex but also somewhat more versatile

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

      If you need to be compatible all the way back to Python 2.4, you can use subprocess.call() and implement your own error checking:

      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 using subprocess?

      • Security: 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 interpret, 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 little additional protection.
      • Error handling: It doesn't actually give us any more error detection, we're still depending on the retcode in either case; but the behavior to explicitly raise an exception in the case of an error will certainly help you notice if there is a failure (though in some scenarios, a traceback might not at all be more helpful than simply ignoring the error).
      • Spawns a (non-blocking) subprocess: We don't need to wait for the child process, since we're by problem statement starting a separate process.

      To the objection "But subprocess is preferred." However, os.system() is not deprecated, and it's in some sense the simplest tool for this particular job. Conclusion: using os.system() is therefore also a correct answer.

      A marked disadvantage is that the Windows start command requires you to pass in shell=True which negates most of the benefits of using subprocess.

    0 讨论(0)
  • 2020-11-22 10:59

    If you want to go the subprocess.call() way, it should look like this on 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:

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

    but only if there are no spaces in the FILE_NAME.

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

    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.

    0 讨论(0)
  • 2020-11-22 11:03

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

    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))
    
    0 讨论(0)
  • 2020-11-22 11:06

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

    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 讨论(0)
  • 2020-11-22 11:09
    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])
    
    0 讨论(0)
提交回复
热议问题