xFinder - Ricerca file e cartelle [Python]

Forum di discussioni su Python
Rispondi
FrancyDotNet
Moderatore
Moderatore
Messaggi: 969
Iscritto il: 01/05/2024, 23:26

xFinder - Ricerca file e cartelle [Python]

Messaggio da FrancyDotNet »

:info: Versione 1.0:Questo è il programma di base. Effettua la ricerca di files o cartella all'interno di una directory in modo ricorsivo e nei risultati ne restituisce i dettagli. Non sono state incluse alcune funzioni che ne avrebbero ottimizzato l'utilizzo proprio per fornire una miglior leggibilità del codice e rendere semplice il concetto di ricerca.

Codice: Seleziona tutto

import os

def search_files_and_folder(root_folder, search_name):
    results = []
    for root, dirs, files in os.walk(root_folder):
        if search_name in dirs + files:
            path = os.path.join(root, search_name)
            name, ext = os.path.splitext(search_name)
            dir_path = os.path.dirname(path)
            dir_path = dir_path.replace('/', '\\')
            size = os.path.getsize(path)
            size_kb = "{:,} KB".format(round(size/1024, 1))
            results.append((name, dir_path, ext, size_kb))
    return results

# Definisci la cartella di partenza per la ricerca
cartella_di_partenza = "F:/Dev/Progetti"

# Definisci il nome del file o della cartella da cercare
nome_file_o_cartella = "array.wad"

# Chiama la funzione search_files_and_folder per cercare il file o la cartella
results = search_files_and_folder(cartella_di_partenza, nome_file_o_cartella)

# Stampa i risultati della ricerca
if results:
    print(f"Trovati {len(results)} risultati per '{nome_file_o_cartella}':\n")
    for result in results:
        print(f"Nome: {result[0]}")
        print(f"Percorso: {result[1]}")
        print(f"Estensione: {result[2]}")
        print(f"Dimensioni: {result[3]}")
else:
    print(f"Nessun risultato trovato per '{nome_file_o_cartella}' nella cartella '{cartella_di_partenza}'.")
Considerazioni finali: Il codice è abbastanza efficiente, ma ci sono alcune possibili ottimizzazioni che si potrebbero considerare:
  • Utilizzare la libreria pathlib invece di os per le operazioni sui percorsi:
    La libreria pathlib offre una sintassi più pulita e orientata agli oggetti per le operazioni sui percorsi, ed è generalmente più facile da usare rispetto alla libreria os. Potresti provare a riscrivere la funzione search_files_and_folder utilizzando pathlib per migliorare la leggibilità e la manutenibilità del codice.
  • Utilizzare la funzione os.scandir invece di os.walk:
    La funzione os.scandir è più veloce di os.walk, poiché restituisce direttamente gli oggetti DirEntry relativi ai file e alle cartelle nella directory specificata. In questo modo, non è necessario eseguire la ricorsione sui sotto-directory e risparmi tempo.
  • Utilizzare il modulo multiprocessing per parallelizzare la ricerca:
    Se devi cercare in una grande quantità di file, potrebbe essere utile utilizzare il modulo multiprocessing per parallelizzare la ricerca su più processi. In questo modo, potresti sfruttare i multi-core del tuo processore e ridurre significativamente il tempo di esecuzione.
  • Utilizzare un generatore di espressioni per ridurre il consumo di memoria:
    Invece di creare una lista di risultati, potresti utilizzare le espressioni generator per ridurre il consumo di memoria. In questo modo, la funzione restituirà un generatore, che permette di ottenere i risultati man mano che vengono generati, anziché doverli memorizzare tutti in memoria.
  • Utilizzare pathlib per la formattazione dei percorsi:
    Quando devi convertire un percorso in un percorso Windows, anziché usare dir_path.replace('/', '\\'), potresti utilizzare il metodo as_posix() di pathlib.Path, che converte il percorso in un percorso POSIX e lo formatta automaticamente correttamente per la piattaforma corrente.
  • Utilizzarere la funzione fnmatch.fnmatch() per controllare se il nome del file o della cartella corrisponde al pattern specificato nella variabile search_name, che può contenere il carattere jolly * per rappresentare qualsiasi stringa di caratteri.
FrancyDotNet
Moderatore
Moderatore
Messaggi: 969
Iscritto il: 01/05/2024, 23:26

Re: xFinder - Ricerca file e cartelle [Python]

Messaggio da FrancyDotNet »

In questo post vorrei presentare le varianti del programma base, ovvero le versioni 1.5 - 2.0 - 3.0 che non sono altro che un'evoluzione rispetto alla precedente. Lo scopo sarebbe quello di mostrare le diverse opportunità che possono essere utilizzare quando si effettua una ricerca.



:info: Versione 1.5: Questa è una versione migliorata del programma di base inserendo le funzioni "seen" e "yield". È stato introdotto l'utilizzo della libreria "fnmatch" per un maggior controllo sul nome del percorso e per una gestione più flessibile dei caratteri jolly (come * oppure ?).
Inoltre è stata aggiunta una funzione per misurare il tempo impiegato durante la ricerca, una barra del progresso ed infine sono state aggiunte le informazioni sulle date e sui permessi.

Codice: Seleziona tutto

import os
import time
import fnmatch
from datetime import datetime

def search_files_and_folder(root_folder, search_filename):
    # Qui vengono contati quanti files e cartelle dovranno essere elaborati
    mid_time = time.time()
    total_files = 0
    for root, dirs, files in os.walk(root_folder):
        total_files += len(dirs + files)
    current_file = 0
    print (f"Conteggio totale files e cartelle: {total_files} ; Eseguito in: {time.time() - mid_time:.2f} secondi")
    # Qui parte la funzione di ricerca
    seen = set()  # set di path già visitati
    for root, dirs, files in os.walk(root_folder):
        for filename in (dirs + files):
            current_file += 1
            progress_bar(current_file, total_files)
            if fnmatch.fnmatch(filename, search_filename) and filename not in seen:
                path = os.path.join(root, filename)
                name = os.path.basename(path)
                ext = os.path.splitext(path)[1]
                dir_path = os.path.dirname(path)
                dir_path = os.path.normpath(os.path.join(dir_path))
                size = os.path.getsize(path)
                size_kb = "{:,} KB".format(round(size/1024, 1))
                last_modified = datetime.fromtimestamp(os.path.getmtime(path)).strftime('%d/%m/%Y')
                creation_time = datetime.fromtimestamp(os.path.getctime(path)).strftime('%d/%m/%Y')
                permissions = oct(os.stat(path).st_mode)[-3:]
                seen.add(filename)
                yield (name, dir_path, ext, size_kb, last_modified, creation_time, permissions)
    print("\n")
    return results

# Imposta la barra del progresso
def progress_bar(current, total):
    toolbar_width = 40
    percent = float(current) * 100 / total
    bar_width = int(percent / 100 * toolbar_width)
    print(f"Progresso: [{'#' * bar_width}{' ' * (toolbar_width - bar_width)}] {percent:.1f}% ", end="\r")

# Definisci la cartella di partenza per la ricerca
cartella_di_partenza = "C:/tmp"

# Definisci il nome del file o della cartella da cercare
nome_file_o_cartella = "array*"

# Misura il tempo di esecuzione della ricerca
start_time = time.time()

# Chiama la funzione search_files_and_folder per cercare il file o la cartella
results = search_files_and_folder(cartella_di_partenza, nome_file_o_cartella)

# Stampa i risultati della ricerca
if results:
    print(f"Trovati i seguenti risultati per '{nome_file_o_cartella}':\n")
    for result in results:
        print("\n")
        print(f"Nome: {result[0]}")
        print(f"Percorso: {result[1]}")
        print(f"Estensione: {result[2]}")
        print(f"Dimensioni: {result[3]}")
        print(f"Ultima modifica: {result[4]}")
        print(f"Data di creazione: {result[5]}")
        print(f"Permessi: {result[6]}\n")
else:
    print(f"Nessun risultato trovato per '{nome_file_o_cartella}' nella cartella '{cartella_di_partenza}'.")

# Stampa il tempo di esecuzione della ricerca
print(f"Tempo di esecuzione complessivo: {time.time() - start_time:.2f} secondi")



:info: Versione 2.0: Il programma base è stato modificato per utilizzare un sistema di caching. Inoltre è stata aggiunta una funzione per misurare il tempo impiegato durante la ricerca ed infine sono state aggiunte le informazioni sulle date e sui permessi.

Codice: Seleziona tutto

import os
import time
from datetime import datetime

class SmartCache:
    def __init__(self):
        self.cache = {}

    def search(self, root_folder, search_filename):
        if search_filename in self.cache:
            # Ritorna i risultati della cache
            return self.cache[search_filename]

        # Cerca i file e le cartelle
        results = []
        for root, dirs, files in os.walk(root_folder):
            if search_filename in dirs + files:
                path = os.path.join(root, search_filename)
                name, ext = os.path.splitext(search_filename)
                dir_path = os.path.dirname(path)
                dir_path = dir_path.replace('/', '\\')
                size = os.path.getsize(path)
                size_kb = "{:,} KB".format(round(size/1024, 1))
                last_modified = datetime.fromtimestamp(os.path.getmtime(path)).strftime('%d/%m/%Y')
                creation_time = datetime.fromtimestamp(os.path.getctime(path)).strftime('%d/%m/%Y')
                permissions = oct(os.stat(path).st_mode)[-3:]
                results.append((name, dir_path, ext, size_kb, last_modified, creation_time, permissions))

        # Salva i risultati nella cache
        self.cache[search_filename] = results

        return results

# Definisci la cartella di partenza per la ricerca
cartella_di_partenza = "C:/tmp"

# Definisci il nome del file o della cartella da cercare
nome_file_o_cartella = "array.wad"

# Misura il tempo di esecuzione della ricerca
start_time = time.time()

# Crea un oggetto SmartCache
cache = SmartCache()

# Chiama il metodo search della cache per cercare il file o la cartella
results = cache.search(cartella_di_partenza, nome_file_o_cartella)

# Stampa i risultati della ricerca
if results:
    print(f"Trovati {len(results)} risultati per '{nome_file_o_cartella}':\n")
    for result in results:
        print(f"Nome: {result[0]}")
        print(f"Percorso: {result[1]}")
        print(f"Estensione: {result[2]}")
        print(f"Dimensioni: {result[3]}")
        print(f"Ultima modifica: {result[4]}")
        print(f"Data di creazione: {result[5]}")
        print(f"Permessi: {result[6]}\n")
else:
    print(f"Nessun risultato trovato per '{nome_file_o_cartella}' nella cartella '{cartella_di_partenza}'.")

# Stampa il tempo di esecuzione della ricerca
print(f"Tempo di esecuzione: {time.time() - start_time:.2f} secondi")



:info: Versione 3.0: Questa è una versione migliorata del programma di base inserendo le funzioni "seen" e "yield". Inoltre è stata aggiunta una funzione per misurare il tempo impiegato durante la ricerca ed infine sono state aggiunte le informazioni sulle date e sui permessi.

Codice: Seleziona tutto

import os
import time
from datetime import datetime

def search_files_and_folder(root_folder, search_filename):
    seen = set()  # set di path già visitati
    for root, dirs, files in os.walk(root_folder):
        for filename in files:
            if search_filename == filename and filename not in seen:
                path = os.path.join(root, filename)
                name, ext = os.path.splitext(filename)
                dir_path = os.path.dirname(path)
                dir_path = dir_path.replace('/', '\\')
                size = os.path.getsize(path)
                size_kb = "{:,} KB".format(round(size/1024, 1))
                last_modified = datetime.fromtimestamp(os.path.getmtime(path)).strftime('%d/%m/%Y')
                creation_time = datetime.fromtimestamp(os.path.getctime(path)).strftime('%d/%m/%Y')
                permissions = oct(os.stat(path).st_mode)[-3:]
                seen.add(filename)
                yield (name, dir_path, ext, size_kb, last_modified, creation_time, permissions)

# Definisci la cartella di partenza per la ricerca
cartella_di_partenza = "C:/tmp"

# Definisci il nome del file o della cartella da cercare
nome_file_o_cartella = "array.wad"

# Misura il tempo di esecuzione della ricerca
start_time = time.time()

# Chiama la funzione search_files_and_folder per cercare il file o la cartella
results = search_files_and_folder(cartella_di_partenza, nome_file_o_cartella)

# Stampa i risultati della ricerca
if results:
    print(f"Trovati i seguenti risultati per '{nome_file_o_cartella}':\n")
    for result in results:
        print(f"Nome: {result[0]}")
        print(f"Percorso: {result[1]}")
        print(f"Estensione: {result[2]}")
        print(f"Dimensioni: {result[3]}")
        print(f"Ultima modifica: {result[4]}")
        print(f"Data di creazione: {result[5]}")
        print(f"Permessi: {result[6]}\n")
else:
    print(f"Nessun risultato trovato per '{nome_file_o_cartella}' nella cartella '{cartella_di_partenza}'.")

# Stampa il tempo di esecuzione della ricerca
print(f"Tempo di esecuzione complessivo: {time.time() - start_time:.2f} secondi")
FrancyDotNet
Moderatore
Moderatore
Messaggi: 969
Iscritto il: 01/05/2024, 23:26

Re: xFinder - Ricerca file e cartelle [Python]

Messaggio da FrancyDotNet »

:coool: Versione finale con interfaccia grafica!!! Scrivere il progetto aggiornato + link a GitHub!

Codice: Seleziona tutto

import os
from pathlib import Path
from datetime import datetime
import math
import fnmatch
import tkinter as tk
from tkinter import ttk, messagebox, filedialog

# Flag per l'interruzione della ricerca
interrupt_flag = False

def inizializza_avvio():
    percorso_corrente = os.getcwd().replace('/', '\\')
    cb1.set(percorso_corrente)
    
    for unit in get_active_drive_letters():
        cb1["values"] = list(cb1["values"]) + [unit]
    cb1["values"] = list(cb1["values"]) + [percorso_corrente]

    btn3.config(state=tk.DISABLED)

def get_active_drive_letters():
    drive_letters = []
    for drive in range(ord('A'), ord('Z') + 1):
        drive_letter = chr(drive) + ":\\"
        if os.path.isdir(drive_letter):
            drive_letters.append(drive_letter)
    return drive_letters

def search_files_and_folder(root_folder, search_name):
    global interrupt_flag
    results = []
    search_name_lower = search_name.lower()
    use_wildcard = "*" in search_name
    
    for root, dirs, files in os.walk(root_folder):
        for item in dirs + files:
            if interrupt_flag:
                interrupt_flag = True
                return results
            if (use_wildcard and fnmatch.fnmatch(item, search_name)) or (not use_wildcard and search_name_lower in item.lower()):
                path = os.path.join(root, item)
                size = os.path.getsize(path)
                size_str = format_size(size)
                name, ext = os.path.splitext(item)
                creation_time = datetime.fromtimestamp(os.path.getctime(path)).strftime('%d %B %Y')
                last_modified = datetime.fromtimestamp(os.path.getmtime(path)).strftime('%d %B %Y')
                results.append((item, path, size_str, ext, creation_time, last_modified))
    return results


def interrupt_search():
    global interrupt_flag
    interrupt_flag = True


def format_size(size_bytes):
    if size_bytes == 0:
        return "0 B"
    size_names = ("Byte", "KB", "MB", "GB", "TB")
    i = int(pow(1024, math.floor(math.log(size_bytes, 1024))))
    return f"{size_bytes / i:.0f} {size_names[int(math.log(i, 1024))]}"

def on_search_click():
    search_foldername = cb1.get()
    search_filename = cb0.get()

    tree.delete(*tree.get_children())
    btn3.config(state=tk.NORMAL)

    if search_foldername and search_filename:
        results = search_files_and_folder(search_foldername, search_filename)
        for result in results:
            tree.insert("", 1, text=str(result[0]), values=(result[1], result[2], result[3], result[4], result[5]))
    else:
        messagebox.showwarning("Attenzione", "Inserisci sia il percorso della cartella che il nome del file/cartella da cercare.")

    btn3.config(state=tk.DISABLED)

def callBrowseDir():
    answer = filedialog.askdirectory(parent=finestra, initialdir=os.getcwd(), title="Please select a folder:")
    if answer:
        cb1["values"] = list(cb1["values"]) + [answer.replace('/', '\\')]
        cb1.set(answer.replace('/', '\\'))

finestra = tk.Tk()
finestra.title("PowerApps - xFinder")
finestra.geometry("800x480")
finestra.iconbitmap('images/Search95.ico')
finestra.resizable(False, False)

#--- Creazione Frame con 3 schede ---
nb = ttk.Notebook(finestra)
pg1 = ttk.Frame(nb)
nb.add(pg1, text="Nome e percorso")
pg2 = ttk.Frame(nb)
nb.add(pg2, text="Data")
pg3 = ttk.Frame(nb)
nb.add(pg3, text="Avanzate")
nb.select(pg1)
nb.place(x=4, y=4, height=184, width=690)

#--- Contenuto Frame #1 ---
lbl1 = ttk.Label(pg1, anchor='e', text = "Nome:")
lbl1.place(x=10, y=20, height=25, width=54)

cb0 = ttk.Combobox(pg1)
cb0.place(x=70, y=20, height=25, width=600)

lbl2 = ttk.Label(pg1, anchor='e', text = "Cerca in:")
lbl2.place(x=10, y=60, height=25, width=54)

cb1 = ttk.Combobox(pg1, state='readonly')
cb1.place(x=70, y=60, height=25, width=500)

btn1 = ttk.Button(pg1, text = "Sfoglia", command=callBrowseDir)
btn1.place(x=580, y=60, height=25, width=90)

varCheck_1 = tk.IntVar()
chk1 = ttk.Checkbutton(pg1, text = "Ricerca nelle sottocartelle", onvalue = 0, offvalue = 1, variable = varCheck_1)
chk1.place(x=70, y=100, height=25, width=160)

##---Contenuto Frame #2---

##---Contenuto Frame #3---

#--- Contenuto Finestra principale ---
btn2 = ttk.Button(finestra, text = "Trova", command=on_search_click)
btn2.place(x=700, y=26, height=25, width=90)

btn3 = ttk.Button(finestra, text = "Interrompi", command=interrupt_search)
btn3.place(x=700, y=56, height=25, width=90)

tree = ttk.Treeview(finestra)
tree["columns"]=("#0", "#1", "#2", "#3", "#4", "#5")
tree.column("#0", width=200, minwidth=200)
tree.column("#1", width=220, minwidth=220)
tree.column("#2", width=80, minwidth=80)
tree.column("#3", width=50, minwidth=50)
tree.column("#4", width=100, minwidth=100)
tree.column("#5", width=100, minwidth=100)
tree.heading("#0",text="Nome")
tree.heading("#1", text="Nella cartella")
tree.heading("#2", text="Dimensione")
tree.heading("#3", text="Tipo")
tree.heading("#4", text="Data creazione")
tree.heading("#5", text="Data modifica")
tree.place(x=4, y=200, height=266, width=770)

vsb = ttk.Scrollbar(finestra, orient="vertical", command=tree.yview)
vsb.place(x=774, y=200, height=266)
tree.configure(yscrollcommand=vsb.set)

if __name__ == "__main__":
    inizializza_avvio()

finestra.mainloop()
Rispondi

Torna a “Python”