Python, как открыть любой файл без явного вызова приложения [duplicate]

NullPointerException s - исключения, возникающие при попытке использовать ссылку, которая указывает на отсутствие местоположения в памяти (null), как если бы она ссылалась на объект. Вызов метода по нулевой ссылке или попытка получить доступ к полю нулевой ссылки вызовет функцию NullPointerException. Они наиболее распространены, но другие способы перечислены на странице NullPointerException javadoc.

Вероятно, самый быстрый пример кода, который я мог бы придумать для иллюстрации NullPointerException, be:

public class Example {

    public static void main(String[] args) {
        Object obj = null;
        obj.hashCode();
    }

}

В первой строке внутри main я явно устанавливаю ссылку Object obj равной null. Это означает, что у меня есть ссылка, но она не указывает на какой-либо объект. После этого я пытаюсь обработать ссылку так, как если бы она указывала на объект, вызывая метод на нем. Это приводит к NullPointerException, потому что нет кода для выполнения в местоположении, на которое указывает ссылка.

(Это техничность, но я думаю, что она упоминает: ссылка, которая указывает на null, равна 't то же, что и указатель C, указывающий на недопустимую ячейку памяти. Нулевой указатель буквально не указывает на в любом месте , который отличается от указаний на местоположение, которое оказывается недопустимым.)

96
задан Francesco Montesano 2 April 2015 в 07:22
поделиться

13 ответов

В Mac OS вы можете использовать команду «open». Существует вызов Windows API, который делает что-то подобное, но я не помню его вслух.

Update

Хорошо, команда «start» сделает это, так что это должно работать

Mac OS / X:

os.system("open "+filename)

Windows:

os.system("start "+filename)

Многое позднее обновление Edward: os.system работает, но он работает только с именами файлов, которые не имеют пробелов в папках и файлах в имени файла (например, A: \ abc \ def \ a.txt) .

Позднее обновление

Хорошо, ясно, что это глупое споры продолжаются, поэтому давайте просто посмотрим на это с помощью подпроцесса.

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

. Каковы преимущества этого? Теоретически это более безопасно - но на самом деле нам нужно выполнить командную строку так или иначе; в любой среде нам нужна среда и службы для интерпретации, получения путей и т. д. В любом случае мы не выполняем произвольный текст, поэтому он не имеет встроенного «но вы можете набрать 'filename ; rm -rf /'», и если имя файла может быть повреждено, использование subprocess.call не дает нам никакой защиты.

Это фактически не дает нам больше обнаружения ошибок, мы все еще в зависимости от retcode в любом случае. Нам не нужно ждать дочернего процесса, так как мы имеем дело с выражением проблемы, начиная отдельный процесс.

«Но subprocess является предпочтительным». Однако os.system() не является устаревшим, и это самый простой инструмент для этой конкретной работы.

Заключение: использование os.system() - это самый простой и простой способ сделать это, и, следовательно, правильный ответ.

59
ответ дан Pietu1998 18 August 2018 в 20:35
поделиться
  • 1
    В зависимости от того, где происходит filename, это прекрасный пример того, почему os.system () небезопасна и плоха. подпроцесс лучше. – Devin Jeanpierre 28 March 2009 в 17:36
  • 2
    Ответ Ник выглядел хорошо для меня. Ничего не мешало. Объяснение вещей с использованием неправильных примеров нелегко оправдано. – Devin Jeanpierre 29 March 2009 в 18:10
  • 3
    Это менее безопасно и менее гибко, чем использование подпроцесса. Это звучит неправильно для меня. – Devin Jeanpierre 29 March 2009 в 19:35
  • 4
    Конечно, это важно. Это разница между хорошим ответом и плохим ответом (или ужасным ответом). Документы для os.system () сами говорят «Использовать модуль подпроцесса». Что еще нужно? Этого хватит для меня. – Devin Jeanpierre 30 March 2009 в 20:46
  • 5
    Я чувствую себя немного неохотно, чтобы возобновить эту дискуссию, но я думаю, что «позднее обновление» раздел полностью ошибочно. Проблема с os.system() заключается в том, что она использует оболочку (и вы не выполняете никаких экранов здесь, так что Bad Things будет происходить для вполне допустимых имен файлов, которые содержат метасимволы оболочки). Причина, по которой subprocess.call() является предпочтительной, заключается в том, что вы можете обойти оболочку с помощью subprocess.call(["open", filename]). Это работает для всех допустимых имен файлов и не вызывает уязвимости оболочки, даже для ненадежных имен файлов. – Sven Marnach 23 April 2012 в 15:55

Я предпочитаю:

os.startfile(path, 'open')

Обратите внимание, что этот модуль поддерживает имена файлов, которые имеют пробелы в своих папках и файлах, например.

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

( python docs ) 'open' не нужно добавлять (это значение по умолчанию). В документах упоминается, что это похоже на двойной щелчок на значке файла в Проводнике Windows.

Это решение - только окна.

29
ответ дан angussidney 18 August 2018 в 20:35
поделиться
  • 1
    Это только ветровка. – Noah 12 January 2009 в 16:35
  • 2
    Благодарю. Я не заметил доступности, так как документы добавили его в последний абзац. В большинстве других разделов примечание о доступности занимает свою собственную линию. – DrBloodmoney 12 January 2009 в 18:14

Если вам нужно использовать эвристический метод, вы можете рассмотреть webbrowser. Это стандартная библиотека и, несмотря на ее имя, она также попытается открыть файлы:

Обратите внимание, что на некоторых платформах, пытаясь открыть имя файла с помощью этой функции, может работать и запускать связанную с операционной системой программу , Однако это не поддерживается и не переносится. ( Ссылка )

Я пробовал этот код, и он отлично работал в Windows 7 и Ubuntu Natty:

import webbrowser
webbrowser.open("path_to_file")

Этот код также работает отлично в Windows XP Professional, используя Internet Explorer 8.

14
ответ дан Artjom B. 18 August 2018 в 20:35
поделиться
  • 1
    Насколько я могу судить, это, безусловно, лучший ответ. Кажется кросс-платформенным и нет необходимости проверять, какая платформа используется или импортировать os, платформу. – polandeer 9 May 2013 в 00:37
  • 2
    Но это не похоже на Mac. – jonathanrocher 28 March 2014 в 22:20
  • 3
    @jonathanrocher: Я вижу поддержку Mac в исходном коде . Он использует open location там, который должен работать, если вы укажете путь как действительный URL-адрес. – jfs 7 August 2015 в 19:14
  • 4
    macOS: import webbrowser webbrowser.open("file:///Users/nameGoesHere/Desktop/folder/file.py") – Dani Springer 17 December 2017 в 23:53

os.startfile (путь, 'open') под окнами хорош, потому что, когда в каталоге существуют пробелы, os.system ('start', path_name) не может правильно открыть приложение и когда i18n существует в каталоге , os.system необходимо изменить юникод на кодек консоли в Windows.

1
ответ дан BearPy 18 August 2018 в 20:35
поделиться

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.

4
ответ дан bFloch 18 August 2018 в 20:35
поделиться
  • 1
    Другим обходным решением является присвоение ему заголовка в кавычках, например. start "Title" "C:\long path to\file.avi" – user3364825 21 May 2014 в 14:45

В 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))
0
ответ дан Ch.Idea 18 August 2018 в 20:35
поделиться

Просто для полноты (это не было в вопросе), xdg-open будет делать то же самое в Linux.

28
ответ дан dF. 18 August 2018 в 20:35
поделиться
  • 1
    +1 Обычно респонденты не должны отвечать на вопросы, которые не задавались, но в этом случае я считаю, что это очень актуально и полезно для сообщества SO в целом. – demongolem 3 November 2012 в 17:09

Если вы хотите пойти по пути 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"

, что и делает код сверху.

3
ответ дан Edward 18 August 2018 в 20:35
поделиться

Я довольно поздно для партии, но вот решение, использующее windows api. Это всегда открывает связанное приложение.

import ctypes

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

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

Множество магических констант. Первый нуль - это hwnd текущей программы. Может быть нулевым. Остальные два нули - это необязательные параметры (параметры и каталог). 5 == SW_SHOW, он указывает, как выполнить приложение. Подробнее читайте в документах ShellExecute API .

1
ответ дан George 18 August 2018 в 20:35
поделиться

на mac os вы можете вызвать 'open'

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

, это откроет файл с помощью TextEdit или любое другое приложение будет установлено по умолчанию для этого типа файла

0
ответ дан lcvinny 18 August 2018 в 20:35
поделиться
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])
21
ответ дан Nicu Tofan 18 August 2018 в 20:35
поделиться
  • 1
    Да, я не знал о начальном файле. Было бы неплохо, если бы Mac и Linux-версии Python получили подобную семантику. – Nick 12 January 2009 в 19:27
  • 2
    Соответствующая ошибка python: bugs.python.org/issue3177 - предоставить хороший патч, и он может быть принят =) – gnud 18 October 2009 в 21:01

Используйте модуль subprocess, доступный на Python 2.4+, а не os.system(), поэтому вам не нужно иметь дело с экранированием оболочки.

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

Двойные круглые скобки связаны с тем, что subprocess.call() хочет, чтобы в качестве первого аргумента была последовательность, поэтому мы используем кортеж здесь. В Linux-системах с Gnome есть также команда gnome-open, которая делает то же самое, но xdg-open является стандартом Free Desktop Foundation и работает в среде рабочего стола Linux.

115
ответ дан Sven Marnach 18 August 2018 в 20:35
поделиться
  • 1
    Использование «start» в subprocess.call () не работает в Windows - запуск на самом деле не является исполняемым. – Tomas Sedovic 18 October 2009 в 20:10
  • 2
    nitpick: на всех linuxen (и, я думаю, большинство BSD) вы должны использовать xdg-open - linux.die.net/man/1/xdg-open – gnud 18 October 2009 в 20:57
  • 3
    запуск в Windows - это команда оболочки, а не исполняемый файл. Вы можете использовать subprocess.call (('start', filepath), shell = True), хотя, если вы работаете в оболочке, вы можете также использовать os.system. – Peter Graham 4 February 2011 в 00:25
  • 4
    import sys ..... – Phoenix 19 November 2017 в 01:08
  • 5

Если вы хотите указать приложение для открытия файла с помощью Mac OS X, используйте это: os.system("open -a [app name] [file name]")

0
ответ дан user 18 August 2018 в 20:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: