1. Ripasso: File vs Path vs Files
Il vecchio e caro File
Già... di codice legacy nei progetti Java ce n’è in abbondanza. Quindi ricordiamo ancora una volta il veterano di Java, la classe File. È presente fin dalla prima versione del linguaggio e consente di lavorare con file e cartelle: verificare se un file esiste, ottenerne il nome, la dimensione, la data di modifica, creare ed eliminare file e cartelle. Come sappiamo, è piena di limiti: parte dei metodi è poco intuitiva, non tutte le operazioni sono supportate in modo multipiattaforma e alcuni metodi restituiscono non un’eccezione, ma semplicemente false (il che non è sempre comodo per il debug).
import java.io.File;
File file = new File("example.txt");
System.out.println("Il file esiste? " + file.exists());
System.out.println("È un file? " + file.isFile());
System.out.println("È una cartella? " + file.isDirectory());
Path e Files: uno sguardo moderno (Java 7+)
Con l’introduzione di Java 7 è arrivato il package java.nio.file, che offre strumenti più potenti e flessibili. Due protagonisti chiave:
- Path — un’interfaccia che descrive il percorso verso un file o una cartella. Si può dire che è una «stringa intelligente»: sa scomporre, unire, analizzare e confrontare i percorsi.
- Files — una classe di utilità con un sacco di metodi statici per lavorare con file e directory: creazione, eliminazione, copia, lettura, scrittura, recupero di informazioni.
import java.nio.file.Path;
import java.nio.file.Paths;
Path path = Paths.get("example.txt");
System.out.println("Percorso: " + path);
Curiosità: la classe Path non è semplicemente una stringa! Conosce i separatori di directory, sa gestire percorsi relativi e assoluti e funziona ugualmente bene su Windows e Linux.
Tabella di confronto tra File e Path/Files
| Criterio | File (API vecchio) | Path + Files (API moderno) |
|---|---|---|
| Sintassi | stile OOP | Combinazione di Path + metodi statici Files |
| Multipiattaforma | Parziale | Eccellente, tiene conto del SO |
| Eccezioni | Non sempre | Quasi sempre |
| Nuove funzionalità | No | Sì (attributi, permessi, link ecc.) |
| Consigliato | Piuttosto no | Sì |
2. Ottenere informazioni su file/cartella
Vediamo come ottenere le informazioni più importanti su un file o una cartella: se l’oggetto esiste, il tipo (file o directory), la dimensione, il nome, il percorso e la cartella padre.
Verifica dell’esistenza
Con File
File file = new File("example.txt");
if (file.exists()) {
System.out.println("Il file esiste!");
} else {
System.out.println("File non trovato.");
}
Con Path e Files
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
Path path = Paths.get("example.txt");
if (Files.exists(path)) {
System.out.println("Il file esiste!");
} else {
System.out.println("File non trovato.");
}
Suggerimento: Per i nuovi progetti usate sempre Path e Files. È più sicuro, più comodo e multipiattaforma.
Verifica del tipo: file o cartella
File
if (file.isFile()) {
System.out.println("È un file.");
} else if (file.isDirectory()) {
System.out.println("È una cartella.");
}
Path + Files
if (Files.isRegularFile(path)) {
System.out.println("È un file.");
} else if (Files.isDirectory(path)) {
System.out.println("È una cartella.");
}
Ottenere la dimensione del file
File
long size = file.length();
System.out.println("Dimensione del file: " + size + " byte");
Path + Files
try {
long size = Files.size(path);
System.out.println("Dimensione del file: " + size + " byte");
} catch (IOException e) {
System.out.println("Errore durante l’ottenimento della dimensione del file: " + e.getMessage());
}
Attenzione: Per una cartella il metodo length() restituisce sempre 0, mentre Files.size(path) lancerà IOException. La dimensione di una cartella è la somma delle dimensioni di tutti i file al suo interno (maggiori dettagli nelle prossime lezioni).
Ottenere il percorso assoluto e relativo
File
System.out.println("Percorso relativo: " + file.getPath());
System.out.println("Percorso assoluto: " + file.getAbsolutePath());
Path
System.out.println("Percorso relativo: " + path);
System.out.println("Percorso assoluto: " + path.toAbsolutePath());
Ottenere il nome del file e la cartella padre
File
System.out.println("Nome del file: " + file.getName());
System.out.println("Cartella padre: " + file.getParent());
Path
System.out.println("Nome del file: " + path.getFileName());
System.out.println("Cartella padre: " + path.getParent());
Trucchetto: Path sa lavorare non solo con i file, ma anche con le cartelle, con percorsi relativi e assoluti, e consente di scomporre facilmente un percorso in parti.
3. Ottenere gli attributi del file
A volte serve sapere non solo la dimensione e il nome del file, ma anche qualcos’altro: data di creazione, data dell’ultima modifica, permessi di accesso.
Data di creazione e ultima modifica
File (limitato)
long lastModified = file.lastModified();
System.out.println("Data dell’ultima modifica: " + new java.util.Date(lastModified));
Svantaggio: Con File non è possibile ottenere la data di creazione del file!
Path + Files
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileTime;
try {
BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class);
FileTime creationTime = attrs.creationTime();
FileTime lastModifiedTime = attrs.lastModifiedTime();
System.out.println("Data di creazione: " + creationTime);
System.out.println("Data dell’ultima modifica: " + lastModifiedTime);
} catch (IOException e) {
System.out.println("Errore durante l’ottenimento degli attributi: " + e.getMessage());
}
Verifica dei permessi di accesso
File
System.out.println("Lettura consentita? " + file.canRead());
System.out.println("Scrittura consentita? " + file.canWrite());
System.out.println("Esecuzione consentita? " + file.canExecute());
Path + Files
System.out.println("Lettura consentita? " + Files.isReadable(path));
System.out.println("Scrittura consentita? " + Files.isWritable(path));
System.out.println("Esecuzione consentita? " + Files.isExecutable(path));
Curiosità: Su Windows i permessi sono più limitati, mentre sui sistemi Unix si possono ottenere e modificare molti più permessi (ad esempio tramite attributi POSIX).
4. Errori tipici nell’ottenere informazioni sui file
Errore n. 1: usare File quando serve Path.
Molti principianti continuano a usare File perché sembra più semplice o «perché così si vede ovunque su Internet». Ma con Path e Files si può fare la stessa cosa in modo più affidabile e moderno.
Errore n. 2: verificare il tipo solo tramite File.
Se usate solo file.isFile() e file.isDirectory(), potreste non considerare i file «speciali» (link simbolici, device). Nell’API moderno ci sono Files.isRegularFile(path), Files.isDirectory(path) e altre verifiche.
Errore n. 3: ignorare le eccezioni.
I metodi Files.size(path) e Files.readAttributes(...) lanciano IOException. Se non gestite le eccezioni, il programma andrà in errore al primo problema di accesso o se il file scompare durante l’esecuzione.
Errore n. 4: aspettarsi di poter ottenere direttamente la dimensione di una cartella.
Il metodo Files.size(path) per una cartella genera un’eccezione. Per conoscerne la dimensione bisogna sommare ricorsivamente le dimensioni di tutti i file al suo interno.
Errore n. 5: verificare i permessi in modo insufficiente.
Anche se il file esiste, potresti non avere i permessi per leggerlo o scriverlo. Verificate sempre i permessi prima delle operazioni: Files.isReadable(path), Files.isWritable(path), Files.isExecutable(path).
GO TO FULL VERSION