在工作中我可以选择多个.xlsx文件,右键单击一个文件将为我提供组合文件以制作.pdf的选项。现在我想在我的一个脚本中使用相同的功能。也就是说,选择多个文件并将这些文件的路径作为参数发送到Python脚本。
我花了一个小时寻找解决方案,但我没有找到任何好的答案。似乎有一些C#答案,但我不知道如何将代码转换为Python。是否有可能实现它?
编辑 - 示例脚本:
import sys, os
for file in sys.argv:
print(file)
os.system("PAUSE")
答案 0 :(得分:2)
编辑:至少在使用上下文菜单
时无法使用我找到了部分解决方案here。但是,如果Internet Explorer处于打开状态,它将无法工作(如何检测到这一点?)。此外,如果打开了多个Windows资源管理器实例,则会计算所有窗口中的所选文件。我为此添加了一张支票。
import win32com.client as win32
import os
import win32ui
def explorer_fileselection():
working_dir = os.getcwd()
clsid = '{9BA05972-F6A8-11CF-A442-00A0C90A8F39}' #Valid for IE as well!
shellwindows = win32.Dispatch(clsid)
files = []
try:
for window in range(shellwindows.Count):
window_URL = shellwindows[window].LocationURL
window_dir = window_URL.split("///")[1].replace("/", "\\")
if window_dir == working_dir:
selected_files = shellwindows[window].Document.SelectedItems()
for file in range(selected_files.Count):
files.append(selected_files.Item(file).Path)
except: #Ugh, need a better way to handle this one
win32ui.MessageBox("Close IE!", "Error")
del shellwindows
return files
print(*explorer_fileselection(), sep="\n")
--- prints the selected files:
C:\Users\oe\Python\ssa\util\test3.docx
C:\Users\oe\Python\ssa\util\__init__.py
C:\Users\oe\Python\ssa\util\explorer_filer.py
C:\Users\oe\Python\ssa\util\test1.xlsx
C:\Users\oe\Python\ssa\util\test2.xls
我想我会在函数中添加*valid_ext
参数,因此我可以像explorer_fileselection("xlsx", "xls")
这样调用来获取Excel文件。
答案 1 :(得分:1)
这实际上是一个Windows问题,并不是非常具体的Python。 您希望Windows shell在shell上下文菜单中显示脚本的菜单项。
要完成此操作,您可以向注册表添加一些密钥。有关如何添加菜单项的说明,请参阅Add menu item to windows context menu only for specific filetype。
之后,当您选择多个文件并将它们发送到脚本时,您将看到这些文件为命令行参数。如果选择10个文件,脚本将运行10次。
答案 2 :(得分:1)
我知道这很晚才在此处发布答案,但是几个月前我曾尝试过Olav的解决方案,但并未完全起作用:工作目录是脚本的工作目录,因此我不得不删除如果条件使其正常工作,但它选择了所有Windows资源管理器窗口中的所有文件(我也希望这样做,因此对我来说部分起作用)。但是现在我回到继续我的项目(助理)的过程中,发现我确实需要这项工作,因此我考虑了这个想法(这并不难想到,但花了几个月的时间我才有了... )。我不知道这个答案是否对其他任何人都有用,但是对我来说,它并不完全,所以我认为我可以改进它,并在此处发布解决方案。这段代码混合了以下答案(我在同一脚本中也一直使用该答案,但从未想过让它们一起工作):https://stackoverflow.com/a/43892579/8228163(我更正为至少在Windows 7下可以工作)和Olav的答案和结果对我有用-该脚本仅在当前Windows资源管理器窗口中检测文件。我认为所有这些工作都可以从Vista(也许我不知道它早于7)到10,但是我不确定。另一个答案是使用XP。当我在Windows 10上启动此脚本时,我认为它可以工作,但是我已经没有10了,所以我不确定(我再次使用7,所以7可以正常工作)。
import win32gui, time
from win32con import PAGE_READWRITE, MEM_COMMIT, MEM_RESERVE, MEM_RELEASE, PROCESS_ALL_ACCESS, WM_GETTEXTLENGTH, WM_GETTEXT
from commctrl import LVS_OWNERDATA, LVM_GETITEMCOUNT, LVM_GETNEXTITEM, LVNI_SELECTED
import os
import struct
import ctypes
import win32api
import datetime
import win32com.client as win32
import win32ui
import psutil
import subprocess
import time
import urllib.parse
clsid = '{9BA05972-F6A8-11CF-A442-00A0C90A8F39}' #Valid for IE as well!
def getEditText(hwnd):
# api returns 16 bit characters so buffer needs 1 more char for null and twice the num of chars
buf_size = (win32gui.SendMessage(hwnd, WM_GETTEXTLENGTH, 0, 0) +1 ) * 2
target_buff = ctypes.create_string_buffer(buf_size)
win32gui.SendMessage(hwnd, WM_GETTEXT, buf_size, ctypes.addressof(target_buff))
return target_buff.raw.decode('utf16')[:-1]# remove the null char on the end
def _normaliseText(controlText):
'''Remove '&' characters, and lower case.
Useful for matching control text.'''
return controlText.lower().replace('&', '')
def _windowEnumerationHandler(hwnd, resultList):
'''Pass to win32gui.EnumWindows() to generate list of window handle,
window text, window class tuples.'''
resultList.append((hwnd, win32gui.GetWindowText(hwnd), win32gui.GetClassName(hwnd)))
def searchChildWindows(currentHwnd,
wantedText=None,
wantedClass=None,
selectionFunction=None):
results = []
childWindows = []
try:
win32gui.EnumChildWindows(currentHwnd,
_windowEnumerationHandler,
childWindows)
except win32gui.error:
# This seems to mean that the control *cannot* have child windows,
# i.e. not a container.
return
for childHwnd, windowText, windowClass in childWindows:
descendentMatchingHwnds = searchChildWindows(childHwnd)
if descendentMatchingHwnds:
results += descendentMatchingHwnds
if wantedText and \
not _normaliseText(wantedText) in _normaliseText(windowText):
continue
if wantedClass and \
not windowClass == wantedClass:
continue
if selectionFunction and \
not selectionFunction(childHwnd):
continue
results.append(childHwnd)
return results
def explorer_fileselection():
global clsid
address_1=""
files = []
shellwindows = win32.Dispatch(clsid)
w=win32gui
window = w.GetForegroundWindow()
#print("window: %s" % window)
if (window != 0):
if (w.GetClassName(window) == 'CabinetWClass'): # the main explorer window
#print("class: %s" % w.GetClassName(window))
#print("text: %s " %w.GetWindowText(window))
children = list(set(searchChildWindows(window)))
addr_edit = None
file_view = None
for child in children:
if (w.GetClassName(child) == 'WorkerW'): # the address bar
addr_children = list(set(searchChildWindows(child)))
for addr_child in addr_children:
if (w.GetClassName(addr_child) == 'ReBarWindow32'):
addr_edit = addr_child
addr_children = list(set(searchChildWindows(child)))
for addr_child in addr_children:
if (w.GetClassName(addr_child) == 'Address Band Root'):
addr_edit = addr_child
addr_children = list(set(searchChildWindows(child)))
for addr_child in addr_children:
if (w.GetClassName(addr_child) == 'msctls_progress32'):
addr_edit = addr_child
addr_children = list(set(searchChildWindows(child)))
for addr_child in addr_children:
if (w.GetClassName(addr_child) == 'Breadcrumb Parent'):
addr_edit = addr_child
addr_children = list(set(searchChildWindows(child)))
for addr_child in addr_children:
if (w.GetClassName(addr_child) == 'ToolbarWindow32'):
text=getEditText(addr_child)
if "\\" in text:
address_1=getEditText(addr_child)[text.index(" ")+1:]
print("Address --> "+address_1)
for window in range(shellwindows.Count):
window_URL = urllib.parse.unquote(shellwindows[window].LocationURL,encoding='ISO 8859-1')
window_dir = window_URL.split("///")[1].replace("/", "\\")
print("Directory --> "+window_dir)
if window_dir==address_1:
selected_files = shellwindows[window].Document.SelectedItems()
for file in range(selected_files.Count):
files.append(selected_files.Item(file).Path)
print("Files --> "+str(files))
while True:
explorer_fileselection()
time.sleep(1)
这将查找活动的Windows资源管理器窗口,获取该窗口的地址,然后将该地址用于Olav的回答,以检查该地址是否等于在Windows资源管理器中打开的地址之一,从而从活动的文件中获取文件窗口。顺便说一句,因为这是脚本,是两个答案的修改后的副本,所以它有这些限制。因此,就像奥拉夫(Olav)的回答“编辑:至少在使用上下文菜单时尚不起作用”一样,这也可能不会起作用,因为它是相同的代码-只是工作目录不同(尽管,我不知道他的意思,但是对于我测试过的方法,它确实有效。就像詹姆斯·肯特(James Kent)的回答一样,这不适用于桌面,仅适用于使用Windows资源管理器打开的窗口。 encoding ='ISO 8859-1'是因为我是葡萄牙语,但是可以更改,只需确保两个目录在没有%?s的情况下相等,否则将不起作用!
由于这个问题只有将近5年,OP可能不再需要它了,但是我需要它并且在任何地方都没有它,所以我想我可以在这里发布它,并且可以帮助其他想要做的人这个。脚本中的代码可用于了解当前Windows资源管理器窗口上的文件,以及获取XP以上版本的Windows(不确定Vista)上的当前Windows资源管理器窗口路径。对于XP,请参阅原始答案(https://stackoverflow.com/a/43892579/8228163),并要从所有Windows资源管理器窗口中获取文件,只需从Olav答案中删除if条件即可。
感谢Olav和James Kent的回答,因为我将花更多的时间试图找出方法(我是Python /任何一种语言的始作俑者-仅仅编码一年,所以本来需要非常多的时间,也许我必须将其与另一种语言混合使用。再次感谢OP,也感谢OP提出问题并让合适的人员在正确的时间回答! (因为Olav在链接上引用的来源已不存在。)
希望这会有所帮助!干杯!
答案 3 :(得分:0)
您是在询问如何获取文件列表,还是在询问如何进行转换?
如果您在询问选择文件(这对我来说是什么样的),您是在寻找GUI解决方案还是命令行解决方案?
你可以使用os.listdir()函数显示文件夹中的所有.xlsx文件是os库,然后将它们过滤到只包含.xlsx的文件,如下所示:
files = [ fi for fi in os.listdir(folder) if fi.endswith(suffix) ]
然后你可以在它们旁边打印带有索引的文件列表,并要求用户输入他们想要选择的文件的索引,如下所示:
for fInd,f in enumerate(files):
print '%s) %s' %(fInd, f)
response = raw_input('select files by indices (coma separated)')
keeperInds = response.split(',')
keeperInds = [int(keeperInd) for keeperInd in keeperInds]
# you should also check to make sure that the selected inds are valid...
selectedFiles = [files[ind] for ind in keeperInds]
将为您提供可以传递到脚本中的所选文件的列表。
如果您真的需要有关从.xlsx文件到pdf的转换的帮助,您可以查看一下 - 您可以通过更改文件格式来更改它以保存.pdfs。 Converting .XLSX to .XLS in Python with win32com.client module