我有一个简单的脚本,可以解析文件并将其内容加载到数据库中。我不需要 UI,但现在我提示用户使用
raw_input
解析文件,这是最不友好的,特别是因为用户无法复制/粘贴路径。我想要一种快速简便的方法来向用户呈现文件选择对话框,他们可以选择文件,然后将其加载到数据库中。 (在我的用例中,如果他们碰巧选择了错误的文件,解析就会失败,即使加载到数据库也不会成为问题。)
import tkFileDialog
file_path_string = tkFileDialog.askopenfilename()
这段代码接近我想要的,但它留下了一个恼人的空框架打开(无法关闭,可能是因为我还没有注册关闭事件处理程序)。
我不必使用 tkInter,但由于它位于 Python 标准库中,因此它是最快、最简单的解决方案的良好候选者。
有什么快速、简单的方法可以在脚本中提示输入文件或文件名而无需任何其他 UI?
如果您不想有任何其他依赖项,Tkinter 是最简单的方法。 要仅显示对话框而不显示任何其他 GUI 元素,您必须使用
withdraw
方法隐藏根窗口:
import tkinter as tk
from tkinter import filedialog
root = tk.Tk()
root.withdraw()
file_path = filedialog.askopenfilename()
Python 2 变体:
import Tkinter, tkFileDialog
root = Tkinter.Tk()
root.withdraw()
file_path = tkFileDialog.askopenfilename()
尝试使用 wxPython:
import wx
def get_path(wildcard):
app = wx.App(None)
style = wx.FD_OPEN | wx.FD_FILE_MUST_EXIST
dialog = wx.FileDialog(None, 'Open', wildcard=wildcard, style=style)
if dialog.ShowModal() == wx.ID_OK:
path = dialog.GetPath()
else:
path = None
dialog.Destroy()
return path
print get_path('*.txt')
pywin32
提供对 GetOpenFileName
win32 函数的访问。来自示例
import win32gui, win32con, os
file_types = "Python Scripts\0*.py;*.pyw;*.pys\0Text files\0*.txt\0"
customfilter = "Other file types\0*.*\0"
fname, customfilter, flags = win32gui.GetOpenFileNameW(
InitialDir=os.environ["temp"],
Flags=win32con.OFN_ALLOWMULTISELECT | win32con.OFN_EXPLORER,
File="somefilename",
DefExt="py",
Title="GetOpenFileNameW",
Filter=file_types,
CustomFilter=customfilter,
FilterIndex=0,
)
print("open file names:", repr(fname))
print("filter used:", repr(customfilter))
print("Flags:", flags)
for k, v in win32con.__dict__.items():
if k.startswith("OFN_") and flags & v:
print("\t" + k)
使用 tkinter (python 2) 或 Tkinter (python 3) 确实可以显示文件打开对话框(请参阅此处的其他答案)。但请注意,该对话框的用户界面已过时,并且与 Windows 10 中可用的较新文件打开对话框不对应。
此外 - 如果您正在寻找将 python 支持嵌入到您自己的应用程序中的方法 - 您很快就会发现 tkinter 库不是开源代码,甚至更多 - 它是商业库。
(例如搜索“activetcl定价”将引导您进入此网页:https://reviews.financesonline.com/p/activetcl/)
所以 tkinter 库对于任何想要嵌入 python 的应用程序来说都是要花钱的。
我自己设法找到了 pythonnet 库:
(麻省理工学院许可证)
使用以下命令可以安装pythonnet:
pip3 install pythonnet
在这里您可以找到使用打开文件对话框的工作示例:
https://stackoverflow.com/a/50446803/2338477
我也在这里复制一个例子:
import sys
import ctypes
co_initialize = ctypes.windll.ole32.CoInitialize
# Force STA mode
co_initialize(None)
import clr
clr.AddReference('System.Windows.Forms')
from System.Windows.Forms import OpenFileDialog
file_dialog = OpenFileDialog()
ret = file_dialog.ShowDialog()
if ret != 1:
print("Cancelled")
sys.exit()
print(file_dialog.FileName)
如果您还错过了更复杂的用户界面 - 请参阅 Demo 文件夹 在 pythonnet git 中。
我不确定是否可以移植到其他操作系统,还没有尝试过,但 .net 5 计划移植到多个操作系统(搜索“.net 5 平台”,https://devblogs.microsoft.com/dotnet /introducing-net-5/ ) - 所以这项技术也是面向未来的。
如果您不需要 UI 或希望程序在 CLI 中运行,您可以将文件路径解析为参数。这将允许您使用 CLI 的自动完成功能来快速找到您需要的文件。
如果脚本除了文件路径输入之外是非交互式的,这可能会很方便。
另一个与操作系统无关的选项,使用 pywebview:
import webview
def webview_file_dialog():
file = None
def open_file_dialog(w):
nonlocal file
try:
file = w.create_file_dialog(webview.OPEN_DIALOG)[0]
except TypeError:
pass # user exited file dialog without picking
finally:
w.destroy()
window = webview.create_window("", hidden=True)
webview.start(open_file_dialog, window)
# file will either be a string or None
return file
print(webview_file_dialog())
环境:Mac 上的 python3.8.6 - 尽管我之前在 Windows 10 上使用过 pywebview。
我刚刚偶然发现了这个仅适用于 Windows 的小技巧:从子进程运行 powershell.exe。
import subprocess
sys_const = ssfDESKTOP # Starts at the top level
# sys_const = 0x2a # Correct value for "Program Files (0x86)" folder
powershell_browse = "(new-object -COM 'Shell.Application')."
powershell_browse += "BrowseForFolder(0,'window title here',0,sys_const).self.path"
ret = subprocess.run(["powershell.exe",powershell_browse], stdout=subprocess.PIPE)
print(ret.stdout.decode())
注意系统文件夹常量的可选使用。 (shldisp.h 中有一个模糊的拼写错误,“Program Files (0x86)”常量被分配错误。我添加了一条具有正确值的注释。我花了一点时间才弄清楚。)
更多信息如下:
如果您不想安装上面提到的任何模块,您可以使用开箱即用的子进程模块通过 PowerShell 来完成此操作,如下所示:
import subprocess
PS_Commands = "Add-Type -AssemblyName System.Windows.Forms;"
PS_Commands += "$fileBrowser = New-Object System.Windows.Forms.OpenFileDialog;"
PS_Commands += "$Null = $fileBrowser.ShowDialog();"
PS_Commands += "echo $fileBrowser.FileName"
file_path = subprocess.run(["powershell.exe", PS_Commands], stdout=subprocess.PIPE)
file_path = file_path.stdout.decode()
file_path = file_path.rstrip()
print(file_path)