Python 查找给定文件的默认应用程序名称
在Linux中,是否有方法询问任何xdg服务或gtk服务,哪个应用程序是给定文件的默认应用程序 我意识到,xdg open实际上将启动正确的应用程序。但是,我希望能够在上下文菜单中显示应用程序的名称。因此,当用户单击菜单项时,它将启动xdg open,从而启动该应用程序 在OSX上,我可以使用LaunchServices进行以下操作:Python 查找给定文件的默认应用程序名称,python,linux,Python,Linux,在Linux中,是否有方法询问任何xdg服务或gtk服务,哪个应用程序是给定文件的默认应用程序 我意识到,xdg open实际上将启动正确的应用程序。但是,我希望能够在上下文菜单中显示应用程序的名称。因此,当用户单击菜单项时,它将启动xdg open,从而启动该应用程序 在OSX上,我可以使用LaunchServices进行以下操作: def getDefaultDarwinApplication(path): import LaunchServices import CoreD
def getDefaultDarwinApplication(path):
import LaunchServices
import CoreData
import urllib
url = CoreData.CFURLRef.URLWithString_("file://"+urllib.quote(path))
os_status, app_ref, appurl = LaunchServices.LSGetApplicationForURL(url, LaunchServices.kLSRolesAll, None, None)
if os_status != 0:
return ""
apppath = app_ref.as_pathname()
name = os.path.basename(apppath).replace(".app", "")
return name
希望在Linux上有类似的东西可以使用。内置python模块最好,但即使是屏幕抓取也能工作。使用
xdgmime
命令。它允许您查询mimetype,然后获取关联的程序,而无需执行它
请注意,这将返回关联的.desktop
文件的名称。然后,您必须找到实际的文件并进一步解析它,以获得程序的真实名称,甚至可以用您想要的任何语言进行本地化,以及磁盘中二进制文件的路径,等等
以下是完整的代码:
import os
import subprocess
import codecs
import ConfigParser
class XDGError(Exception): pass
class FileNotFoundError(Exception): pass
def _get_app_paths():
paths = os.environ.get('XDG_DATA_HOME',
os.path.expanduser('~/.local/share/')).split(os.path.pathsep)
paths.extend(os.environ.get('XDG_DATA_DIRS',
'/usr/local/share/:/usr/share/').split(os.path.pathsep))
return paths
def xdg_query(command, parameter):
p = subprocess.Popen(['xdg-mime', 'query', command, parameter],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output, errors = p.communicate()
if p.returncode or errors:
raise XDGError('xdg-mime returned error code %d: %s' %
(p.returncode, errors.strip()))
return output.strip()
def locate_desktop_file(filename, mode='r', encoding='utf-8',
_paths=_get_app_paths()):
for path in _paths:
for thispath, dirs, files in os.walk(os.path.join(path, 'applications')):
if filename not in files:
continue
fullname = os.path.join(thispath, filename)
try:
return codecs.open(fullname, mode, encoding)
except IOError:
pass
else:
raise FileNotFoundError(filename)
def get_defaults(filename):
filetype = xdg_query('filetype', filename)
desktop_filename = xdg_query('default', filetype)
with locate_desktop_file(desktop_filename) as desktop_file:
parser = ConfigParser.ConfigParser()
parser.readfp(desktop_file, desktop_filename)
return dict(parser.items(parser.sections()[0]))
用法示例:
p = get_defaults('index.html')
print p['name'], p['comment']
下面是一个更简洁的版本,它使用了官方xdg python模块中的一些方法,并使用了@nosklo中的一些优秀代码:
import os
import subprocess
from xdg import BaseDirectory
from xdg import DesktopEntry
class XDGError(Exception): pass
def xdg_query(command, parameter):
p = subprocess.Popen(['xdg-mime', 'query', command, parameter],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output, errors = p.communicate()
if p.returncode or errors:
raise XDGError('xdg-mime returned error code %d: %s' %
(p.returncode, errors.strip()))
return output.strip()
def get_default(filename):
try:
filetype = xdg_query('filetype', filename)
desktop_filename = xdg_query('default', filetype)
except XDGError:
return None
try:
res = BaseDirectory.load_data_paths('applications', desktop_filename)
if not res:
return None
desktop_file = res.next()
except StopIteration:
return None
if not os.path.exists(desktop_file):
return None
return DesktopEntry.DesktopEntry(desktop_file)
以及如何使用它的示例:
entry = get_default("index.html")
if not entry:
print "no default application found"
else:
application_name = entry.getName()
application_path = entry.getExec()
application_icon = entry.getIcon()
我发现这样做更好
import gio
mime_type = gio.content_type_guess('foo.txt')
app_infos = gio.gio.app_info_get_all_for_type(mime_type)
for app_info in app_infos:
print app_info.get_name(), app_info.get_executable(), app_info.get_icon()
# pure bliss
这将无法将每个用户的
.desktop
文件(例如为自定义关联创建的文件)正确定位为$XDG\u DATA\u HOME
或~/.local/share/
中的文件(如果第一个文件未设置)。在转到$XDG\u DATA\u DIRS
中指定的目录之前,您需要查看该目录。这在xdg基本目录规范中有说明。尽管没有我想要的那么清楚。此外,您还必须扫描$xdg_DATA_DIRS/applications
的所有子目录,以查找带有供应商前缀的桌面文件(如xdg菜单规范,章节合并所述)。@Dan D:谢谢您的评论,我已经修改了上面的代码,以遵循该规范。@lunaryorn:Good catch,我现在正在扫描子目录。我还在python xdg中找到了一些代码来帮助实现这一点。从xdg import BaseDirectory obj=BaseDirectory.load_data_path(“applications”,desktop_filename),这将为我们摆脱_get_app_path()方法。