Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package main
- import (
- "context"
- "flag"
- "fmt"
- "io"
- "os"
- "path/filepath"
- "time"
- )
- func main() {
- // Definizione dei flag
- var (
- targetDir string
- timeoutStr string
- helpFlag bool
- bufferSizeKB int
- )
- // Inizializzazione dei flag
- flag.StringVar(&targetDir, "dir", "", "Directory da organizzare (default: directory corrente)")
- flag.StringVar(&targetDir, "d", "", "Directory da organizzare (short version)")
- flag.StringVar(&timeoutStr, "timeout", "30m", "Timeout per operazioni (es: 30s, 5m, 1h)")
- flag.StringVar(&timeoutStr, "t", "30m", "Timeout per operazioni (short version)")
- flag.IntVar(&bufferSizeKB, "buffer", 64, "Dimensione buffer in KB per copia (default: 64KB)")
- flag.IntVar(&bufferSizeKB, "b", 64, "Dimensione buffer in KB per copia (short version)")
- flag.BoolVar(&helpFlag, "help", false, "Mostra questo messaggio di aiuto")
- flag.BoolVar(&helpFlag, "h", false, "Mostra questo messaggio di aiuto (short version)")
- // Parsing dei flag
- flag.Parse()
- // Mostra help se richiesto
- if helpFlag {
- printHelp()
- return
- }
- // Controlla se è stato passato un argomento posizionale (compatibilità con versione precedente)
- if targetDir == "" && flag.NArg() > 0 {
- targetDir = flag.Arg(0)
- }
- // Determina la directory di lavoro
- if targetDir == "" {
- // Usa la directory corrente se non specificata
- var err error
- targetDir, err = os.Getwd()
- if err != nil {
- fmt.Printf("Errore ottenendo directory corrente: %v\n", err)
- os.Exit(1)
- }
- }
- // Parsa il timeout
- timeout, err := time.ParseDuration(timeoutStr)
- if err != nil {
- fmt.Printf("Errore parsing timeout '%s': %v\n", timeoutStr, err)
- fmt.Println("Formati validi: 30s, 5m, 2h, 1h30m, ecc.")
- os.Exit(1)
- }
- // Verifica buffer size
- if bufferSizeKB <= 0 {
- fmt.Printf("Dimensione buffer non valida: %d KB\n", bufferSizeKB)
- os.Exit(1)
- }
- bufferSize := bufferSizeKB * 1024
- fmt.Printf("Configurazione:\n")
- fmt.Printf(" Directory: %s\n", targetDir)
- fmt.Printf(" Timeout: %v\n", timeout)
- fmt.Printf(" Buffer: %d KB\n", bufferSizeKB)
- fmt.Println("----------------------------")
- // Verifica che la directory esista
- info, err := os.Stat(targetDir)
- if err != nil {
- fmt.Printf("Errore accesso directory: %v\n", err)
- os.Exit(1)
- }
- if !info.IsDir() {
- fmt.Printf("%s non è una directory\n", targetDir)
- os.Exit(1)
- }
- // Leggi il contenuto della directory
- entries, err := os.ReadDir(targetDir)
- if err != nil {
- fmt.Printf("Errore lettura directory: %v\n", err)
- os.Exit(1)
- }
- // Contatori per statistiche
- processed := 0
- failed := 0
- skipped := 0
- // Crea contesto con timeout globale
- ctx, cancel := context.WithTimeout(context.Background(), timeout)
- defer cancel()
- for _, entry := range entries {
- // Controlla se il contesto è scaduto
- if ctx.Err() != nil {
- fmt.Printf("\nTimeout raggiunto! Operazione interrotta.\n")
- break
- }
- // Ignora le cartelle
- if entry.IsDir() {
- skipped++
- continue
- }
- filename := entry.Name()
- filePath := filepath.Join(targetDir, filename)
- // Ottieni le informazioni del file
- fileInfo, err := os.Stat(filePath)
- if err != nil {
- fmt.Printf("[ERRORE] Info file %s: %v\n", filename, err)
- failed++
- continue
- }
- // Ottieni la data di creazione/modifica
- creationTime := fileInfo.ModTime()
- // Formatta la data come AAAA-MM-GG
- folderName := creationTime.Format("2006-01-02")
- newDirPath := filepath.Join(targetDir, folderName)
- // Crea la directory se non esiste
- if err := os.MkdirAll(newDirPath, 0755); err != nil {
- fmt.Printf("[ERRORE] Creazione directory %s: %v\n", folderName, err)
- failed++
- continue
- }
- // Costruisci il percorso di destinazione
- destPath := filepath.Join(newDirPath, filename)
- // Copia il file con timeout
- if err := copyFileWithTimeout(ctx, filePath, destPath, bufferSize); err != nil {
- fmt.Printf("[ERRORE] Copia %s: %v\n", filename, err)
- failed++
- continue
- }
- // Elimina il file originale
- if err := os.Remove(filePath); err != nil {
- fmt.Printf("[ERRORE] Eliminazione %s: %v\n", filename, err)
- failed++
- // Tentiamo di eliminare la copia per mantenere la consistenza
- os.Remove(destPath)
- continue
- }
- fmt.Printf("[OK] %s -> %s\n", filename, folderName)
- processed++
- }
- // Controlla se il timeout è scaduto
- if ctx.Err() != nil {
- fmt.Printf("\nATTENZIONE: Timeout raggiunto durante l'operazione!\n")
- }
- fmt.Printf("\nOperazione completata!\n")
- fmt.Printf(" File processati: %d\n", processed)
- fmt.Printf(" File falliti: %d\n", failed)
- fmt.Printf(" Cartelle ignorate: %d\n", skipped)
- if failed == 0 {
- fmt.Println("Tutti i file sono stati organizzati con successo!")
- }
- }
- // copyFileWithTimeout copia un file con timeout e buffer personalizzato
- func copyFileWithTimeout(ctx context.Context, src, dst string, bufferSize int) error {
- // Canale per il risultato dell'operazione
- resultChan := make(chan error, 1)
- // Esegui la copia in una goroutine
- go func() {
- resultChan <- copyFileInternal(src, dst, bufferSize)
- }()
- // Attendi il risultato o il timeout
- select {
- case err := <-resultChan:
- return err
- case <-ctx.Done():
- // Timeout raggiunto
- return fmt.Errorf("timeout: %v", ctx.Err())
- }
- }
- // copyFileInternal esegue la copia effettiva del file
- func copyFileInternal(src, dst string, bufferSize int) error {
- // Apri file sorgente
- sourceFile, err := os.Open(src)
- if err != nil {
- return fmt.Errorf("apertura sorgente: %w", err)
- }
- defer sourceFile.Close()
- // Ottieni info sul file sorgente
- srcInfo, err := sourceFile.Stat()
- if err != nil {
- return fmt.Errorf("info sorgente: %w", err)
- }
- // Crea directory di destinazione se non esiste
- if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
- return fmt.Errorf("creazione directory: %w", err)
- }
- // Crea file destinazione con stessi permessi
- destFile, err := os.OpenFile(dst, os.O_RDWR|os.O_CREATE|os.O_TRUNC, srcInfo.Mode())
- if err != nil {
- return fmt.Errorf("creazione destinazione: %w", err)
- }
- defer destFile.Close()
- // Buffer per la copia
- var buf []byte
- if bufferSize > 0 {
- buf = make([]byte, bufferSize)
- }
- // Copia il file
- var bytesCopied int64
- if buf != nil {
- bytesCopied, err = io.CopyBuffer(destFile, sourceFile, buf)
- } else {
- bytesCopied, err = io.Copy(destFile, sourceFile)
- }
- if err != nil {
- // Cleanup in caso di errore
- destFile.Close()
- os.Remove(dst)
- return fmt.Errorf("copia interrotta (copiati %d byte): %w", bytesCopied, err)
- }
- // Verifica che le dimensioni corrispondano
- if bytesCopied != srcInfo.Size() {
- destFile.Close()
- os.Remove(dst)
- return fmt.Errorf("dimensioni non corrispondono: sorgente=%d, copiati=%d", srcInfo.Size(), bytesCopied)
- }
- // Sincronizza (ignora errori su rete)
- destFile.Sync()
- return nil
- }
- func printHelp() {
- fmt.Println("Organizza File - Strumento per organizzare file per data di creazione")
- fmt.Println()
- fmt.Println("Uso:")
- fmt.Println(" organizza_file [OPZIONI] [DIRECTORY]")
- fmt.Println()
- fmt.Println("Opzioni:")
- fmt.Println(" -d, --dir DIRECTORY Directory da organizzare (default: corrente)")
- fmt.Println(" -t, --timeout DURATA Timeout per operazioni (es: 30s, 5m, 1h)")
- fmt.Println(" default: 30m (30 minuti)")
- fmt.Println(" -b, --buffer KB Dimensione buffer in KB per copia")
- fmt.Println(" default: 64 (64KB)")
- fmt.Println(" -h, --help Mostra questo messaggio")
- fmt.Println()
- fmt.Println("Esempi:")
- fmt.Println(" organizza_file # Usa directory corrente")
- fmt.Println(" organizza_file -d /percorso/foto # Specifica directory")
- fmt.Println(" organizza_file -t 10m /percorso/foto # Con timeout di 10 minuti")
- fmt.Println(" organizza_file -t 2h -b 128 # 2 ore timeout, 128KB buffer")
- fmt.Println(" organizza_file \"\\\\server\\share\" # Percorso di rete Windows")
- fmt.Println()
- fmt.Println("Formato durata timeout:")
- fmt.Println(" s = secondi, m = minuti, h = ore")
- fmt.Println(" Esempi: 30s, 5m, 2h, 1h30m")
- }
Advertisement
Add Comment
Please, Sign In to add comment