cydside

Organize files by date in folders

Feb 1st, 2026
64
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Go 8.14 KB | None | 0 0
  1. package main
  2.  
  3. import (
  4.     "context"
  5.     "flag"
  6.     "fmt"
  7.     "io"
  8.     "os"
  9.     "path/filepath"
  10.     "time"
  11. )
  12.  
  13. func main() {
  14.     // Definizione dei flag
  15.     var (
  16.         targetDir    string
  17.         timeoutStr   string
  18.         helpFlag     bool
  19.         bufferSizeKB int
  20.     )
  21.  
  22.     // Inizializzazione dei flag
  23.     flag.StringVar(&targetDir, "dir", "", "Directory da organizzare (default: directory corrente)")
  24.     flag.StringVar(&targetDir, "d", "", "Directory da organizzare (short version)")
  25.     flag.StringVar(&timeoutStr, "timeout", "30m", "Timeout per operazioni (es: 30s, 5m, 1h)")
  26.     flag.StringVar(&timeoutStr, "t", "30m", "Timeout per operazioni (short version)")
  27.     flag.IntVar(&bufferSizeKB, "buffer", 64, "Dimensione buffer in KB per copia (default: 64KB)")
  28.     flag.IntVar(&bufferSizeKB, "b", 64, "Dimensione buffer in KB per copia (short version)")
  29.     flag.BoolVar(&helpFlag, "help", false, "Mostra questo messaggio di aiuto")
  30.     flag.BoolVar(&helpFlag, "h", false, "Mostra questo messaggio di aiuto (short version)")
  31.  
  32.     // Parsing dei flag
  33.     flag.Parse()
  34.  
  35.     // Mostra help se richiesto
  36.     if helpFlag {
  37.         printHelp()
  38.         return
  39.     }
  40.  
  41.     // Controlla se è stato passato un argomento posizionale (compatibilità con versione precedente)
  42.     if targetDir == "" && flag.NArg() > 0 {
  43.         targetDir = flag.Arg(0)
  44.     }
  45.  
  46.     // Determina la directory di lavoro
  47.     if targetDir == "" {
  48.         // Usa la directory corrente se non specificata
  49.         var err error
  50.         targetDir, err = os.Getwd()
  51.         if err != nil {
  52.             fmt.Printf("Errore ottenendo directory corrente: %v\n", err)
  53.             os.Exit(1)
  54.         }
  55.     }
  56.  
  57.     // Parsa il timeout
  58.     timeout, err := time.ParseDuration(timeoutStr)
  59.     if err != nil {
  60.         fmt.Printf("Errore parsing timeout '%s': %v\n", timeoutStr, err)
  61.         fmt.Println("Formati validi: 30s, 5m, 2h, 1h30m, ecc.")
  62.         os.Exit(1)
  63.     }
  64.  
  65.     // Verifica buffer size
  66.     if bufferSizeKB <= 0 {
  67.         fmt.Printf("Dimensione buffer non valida: %d KB\n", bufferSizeKB)
  68.         os.Exit(1)
  69.     }
  70.     bufferSize := bufferSizeKB * 1024
  71.  
  72.     fmt.Printf("Configurazione:\n")
  73.     fmt.Printf("  Directory: %s\n", targetDir)
  74.     fmt.Printf("  Timeout: %v\n", timeout)
  75.     fmt.Printf("  Buffer: %d KB\n", bufferSizeKB)
  76.     fmt.Println("----------------------------")
  77.  
  78.     // Verifica che la directory esista
  79.     info, err := os.Stat(targetDir)
  80.     if err != nil {
  81.         fmt.Printf("Errore accesso directory: %v\n", err)
  82.         os.Exit(1)
  83.     }
  84.     if !info.IsDir() {
  85.         fmt.Printf("%s non è una directory\n", targetDir)
  86.         os.Exit(1)
  87.     }
  88.  
  89.     // Leggi il contenuto della directory
  90.     entries, err := os.ReadDir(targetDir)
  91.     if err != nil {
  92.         fmt.Printf("Errore lettura directory: %v\n", err)
  93.         os.Exit(1)
  94.     }
  95.  
  96.     // Contatori per statistiche
  97.     processed := 0
  98.     failed := 0
  99.     skipped := 0
  100.  
  101.     // Crea contesto con timeout globale
  102.     ctx, cancel := context.WithTimeout(context.Background(), timeout)
  103.     defer cancel()
  104.  
  105.     for _, entry := range entries {
  106.         // Controlla se il contesto è scaduto
  107.         if ctx.Err() != nil {
  108.             fmt.Printf("\nTimeout raggiunto! Operazione interrotta.\n")
  109.             break
  110.         }
  111.  
  112.         // Ignora le cartelle
  113.         if entry.IsDir() {
  114.             skipped++
  115.             continue
  116.         }
  117.  
  118.         filename := entry.Name()
  119.         filePath := filepath.Join(targetDir, filename)
  120.  
  121.         // Ottieni le informazioni del file
  122.         fileInfo, err := os.Stat(filePath)
  123.         if err != nil {
  124.             fmt.Printf("[ERRORE] Info file %s: %v\n", filename, err)
  125.             failed++
  126.             continue
  127.         }
  128.  
  129.         // Ottieni la data di creazione/modifica
  130.         creationTime := fileInfo.ModTime()
  131.  
  132.         // Formatta la data come AAAA-MM-GG
  133.         folderName := creationTime.Format("2006-01-02")
  134.         newDirPath := filepath.Join(targetDir, folderName)
  135.  
  136.         // Crea la directory se non esiste
  137.         if err := os.MkdirAll(newDirPath, 0755); err != nil {
  138.             fmt.Printf("[ERRORE] Creazione directory %s: %v\n", folderName, err)
  139.             failed++
  140.             continue
  141.         }
  142.  
  143.         // Costruisci il percorso di destinazione
  144.         destPath := filepath.Join(newDirPath, filename)
  145.  
  146.         // Copia il file con timeout
  147.         if err := copyFileWithTimeout(ctx, filePath, destPath, bufferSize); err != nil {
  148.             fmt.Printf("[ERRORE] Copia %s: %v\n", filename, err)
  149.             failed++
  150.             continue
  151.         }
  152.  
  153.         // Elimina il file originale
  154.         if err := os.Remove(filePath); err != nil {
  155.             fmt.Printf("[ERRORE] Eliminazione %s: %v\n", filename, err)
  156.             failed++
  157.             // Tentiamo di eliminare la copia per mantenere la consistenza
  158.             os.Remove(destPath)
  159.             continue
  160.         }
  161.  
  162.         fmt.Printf("[OK] %s -> %s\n", filename, folderName)
  163.         processed++
  164.     }
  165.  
  166.     // Controlla se il timeout è scaduto
  167.     if ctx.Err() != nil {
  168.         fmt.Printf("\nATTENZIONE: Timeout raggiunto durante l'operazione!\n")
  169.     }
  170.  
  171.     fmt.Printf("\nOperazione completata!\n")
  172.     fmt.Printf("  File processati: %d\n", processed)
  173.     fmt.Printf("  File falliti: %d\n", failed)
  174.     fmt.Printf("  Cartelle ignorate: %d\n", skipped)
  175.  
  176.     if failed == 0 {
  177.         fmt.Println("Tutti i file sono stati organizzati con successo!")
  178.     }
  179. }
  180.  
  181. // copyFileWithTimeout copia un file con timeout e buffer personalizzato
  182. func copyFileWithTimeout(ctx context.Context, src, dst string, bufferSize int) error {
  183.     // Canale per il risultato dell'operazione
  184.     resultChan := make(chan error, 1)
  185.  
  186.     // Esegui la copia in una goroutine
  187.     go func() {
  188.         resultChan <- copyFileInternal(src, dst, bufferSize)
  189.     }()
  190.  
  191.     // Attendi il risultato o il timeout
  192.     select {
  193.     case err := <-resultChan:
  194.         return err
  195.     case <-ctx.Done():
  196.         // Timeout raggiunto
  197.         return fmt.Errorf("timeout: %v", ctx.Err())
  198.     }
  199. }
  200.  
  201. // copyFileInternal esegue la copia effettiva del file
  202. func copyFileInternal(src, dst string, bufferSize int) error {
  203.     // Apri file sorgente
  204.     sourceFile, err := os.Open(src)
  205.     if err != nil {
  206.         return fmt.Errorf("apertura sorgente: %w", err)
  207.     }
  208.     defer sourceFile.Close()
  209.  
  210.     // Ottieni info sul file sorgente
  211.     srcInfo, err := sourceFile.Stat()
  212.     if err != nil {
  213.         return fmt.Errorf("info sorgente: %w", err)
  214.     }
  215.  
  216.     // Crea directory di destinazione se non esiste
  217.     if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
  218.         return fmt.Errorf("creazione directory: %w", err)
  219.     }
  220.  
  221.     // Crea file destinazione con stessi permessi
  222.     destFile, err := os.OpenFile(dst, os.O_RDWR|os.O_CREATE|os.O_TRUNC, srcInfo.Mode())
  223.     if err != nil {
  224.         return fmt.Errorf("creazione destinazione: %w", err)
  225.     }
  226.     defer destFile.Close()
  227.  
  228.     // Buffer per la copia
  229.     var buf []byte
  230.     if bufferSize > 0 {
  231.         buf = make([]byte, bufferSize)
  232.     }
  233.  
  234.     // Copia il file
  235.     var bytesCopied int64
  236.     if buf != nil {
  237.         bytesCopied, err = io.CopyBuffer(destFile, sourceFile, buf)
  238.     } else {
  239.         bytesCopied, err = io.Copy(destFile, sourceFile)
  240.     }
  241.  
  242.     if err != nil {
  243.         // Cleanup in caso di errore
  244.         destFile.Close()
  245.         os.Remove(dst)
  246.         return fmt.Errorf("copia interrotta (copiati %d byte): %w", bytesCopied, err)
  247.     }
  248.  
  249.     // Verifica che le dimensioni corrispondano
  250.     if bytesCopied != srcInfo.Size() {
  251.         destFile.Close()
  252.         os.Remove(dst)
  253.  
  254.         return fmt.Errorf("dimensioni non corrispondono: sorgente=%d, copiati=%d", srcInfo.Size(), bytesCopied)
  255.     }
  256.  
  257.     // Sincronizza (ignora errori su rete)
  258.     destFile.Sync()
  259.  
  260.     return nil
  261. }
  262.  
  263. func printHelp() {
  264.     fmt.Println("Organizza File - Strumento per organizzare file per data di creazione")
  265.     fmt.Println()
  266.     fmt.Println("Uso:")
  267.     fmt.Println("  organizza_file [OPZIONI] [DIRECTORY]")
  268.     fmt.Println()
  269.     fmt.Println("Opzioni:")
  270.     fmt.Println("  -d, --dir DIRECTORY    Directory da organizzare (default: corrente)")
  271.     fmt.Println("  -t, --timeout DURATA   Timeout per operazioni (es: 30s, 5m, 1h)")
  272.     fmt.Println("                         default: 30m (30 minuti)")
  273.     fmt.Println("  -b, --buffer KB        Dimensione buffer in KB per copia")
  274.     fmt.Println("                         default: 64 (64KB)")
  275.     fmt.Println("  -h, --help             Mostra questo messaggio")
  276.     fmt.Println()
  277.     fmt.Println("Esempi:")
  278.     fmt.Println("  organizza_file                          # Usa directory corrente")
  279.     fmt.Println("  organizza_file -d /percorso/foto        # Specifica directory")
  280.     fmt.Println("  organizza_file -t 10m /percorso/foto    # Con timeout di 10 minuti")
  281.     fmt.Println("  organizza_file -t 2h -b 128             # 2 ore timeout, 128KB buffer")
  282.     fmt.Println("  organizza_file \"\\\\server\\share\"         # Percorso di rete Windows")
  283.     fmt.Println()
  284.     fmt.Println("Formato durata timeout:")
  285.     fmt.Println("  s = secondi, m = minuti, h = ore")
  286.     fmt.Println("  Esempi: 30s, 5m, 2h, 1h30m")
  287. }
  288.  
Advertisement
Add Comment
Please, Sign In to add comment