[英]Python: Get a list of selected files in Explorer (WIndows 7)
在工作中,我可以選擇多個.xlsx文件,右鍵單擊一個文件將為我提供組合文件以生成.pdf的選項。 現在我想在我的一個腳本中使用相同的功能。 也就是說,選擇多個文件並將這些文件的路徑作為參數發送到Python腳本。
我花了一個小時尋找解決方案,但我沒有找到任何好的答案。 似乎有一些C#答案,但我不知道如何將代碼轉換為Python。 是否有可能實現它?
編輯 - 示例腳本:
import sys, os
for file in sys.argv:
print(file)
os.system("PAUSE")
編輯:至少在使用上下文菜單時不起作用
我在這里找到了部分解決方案。 但是,如果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文件。
這實際上是一個Windows問題,並不是非常具體的Python。 您希望Windows shell在shell上下文菜單中顯示腳本的菜單項。
為此,您可以向注冊表添加一些鍵。 有關如何添加菜單項的說明,請參閱僅針對特定文件類型的“添加”菜單項到Windows上下文菜單 。
之后,當您選擇多個文件並將它們發送到腳本時,您將看到這些文件作為命令行參數。 如果選擇10個文件,腳本將運行10次。
我知道在這里發布一個答案有點“遲到”,但幾個月前我曾嘗試過Olav的解決方案而且它沒有完全發揮作用:工作目錄是腳本的工作目錄,所以我不得不刪除if的條件它工作,但它選擇了所有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的答案“編輯:還沒有工作,至少在使用上下文菜單時”,那么這也不會起作用,因為它是相同的代碼 - 它只是工作目錄不同(盡管如此,我不知道他的意思是什么,但是對於我測試過的,它確實有效)。 就像詹姆斯肯特的回答一樣,這不適用於桌面,只適用於使用Windows資源管理器打開的窗口。 編碼='ISO 8859-1'是因為我是葡萄牙語,但它可以改變,只是確保兩個目錄相等而沒有%?s或者不起作用!
由於這個問題只有近5年的時間,OP可能不再需要它,但是我需要它並且沒有它在任何地方,所以我想我可以在這里發布這個並且可能幫助其他想要這樣做的人。 腳本中的代碼可用於了解當前Windows資源管理器窗口中的文件,並獲取Windows上的當前Windows資源管理器窗口路徑(不確定Vista)。 對於XP,請參閱原始答案( https://stackoverflow.com/a/43892579/8228163 )並從所有Windows資源管理器窗口獲取文件,只需從Olav的答案中刪除if條件。
感謝Olav和James Kent的答案,因為我會花更多的時間試圖找到如何做到這一點(我是一個Python /任何語言的初學者 - 只需編碼一年,所以它會花費很多時間,也許我不得不把它和另一個laguage混在一起)。 再次感謝,也感謝OP提出問題並讓合適的人在合適的時間回答! (作為奧拉夫在鏈接上引用的來源不再存在)。
希望這可以幫助! 干杯!
您是在詢問如何獲取文件列表,還是在詢問如何進行轉換?
如果您在詢問選擇文件(這對我來說是什么樣的),您是在尋找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。 使用win32com.client模塊將.XLSX轉換為Python中的.XLS
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.