File
. Puoi leggere del suo lavoro qui . Ma in Java 7, i creatori del linguaggio hanno deciso di cambiare il modo in cui lavorano con file e directory. Ciò era dovuto al fatto che la classe File
presentava una serie di svantaggi. Ad esempio, non disponeva di un metodo copy()
che consentisse di copiare un file da una posizione a un'altra (una funzionalità apparentemente chiaramente necessaria). Inoltre, la classe File
aveva molti metodi che restituivano boolean
valori. Se si verifica un errore, un metodo di questo tipo restituisce false anziché generare un'eccezione, il che rende molto difficile diagnosticare gli errori e determinarne le cause. Invece di una singola classe, File
apparvero fino a 3 classi: Paths
, Path
e Files
. Beh, per essere precisi, Path
questa è un'interfaccia, non una classe. Scopriamo come differiscono l'uno dall'altro e perché ognuno di essi è necessario. Cominciamo con la cosa più semplice: Paths
.
Percorsi
Paths
è una classe molto semplice con un unico metodo statico get()
. È stato creato esclusivamente per ottenere un oggetto di tipo dalla stringa o dall'URI passato Path
. Non ha altre funzionalità. Ecco un esempio del suo lavoro:
import java.nio.file.Path;
import java.nio.file.Paths;
public class Main {
public static void main(String[] args) {
Path testFilePath = Paths.get("C:\\Users\\Username\\Desktop\\testFile.txt");
}
}
Non è la classe più difficile, vero? :) Bene, dato che abbiamo un oggetto di tipo Path
, scopriamo cos'è Path
e perché è necessario :)
Sentiero
Path
, nel complesso, è un analogo ridisegnato del File
. È molto più facile lavorare con che con File
. Innanzitutto , molti metodi di utilità (statici) sono stati rimossi e spostati nella classe Files
. In secondo luogo , Path
sono stati ordinati i valori restituiti dai metodi. Nella classe, File
i metodi hanno restituito this String
, that boolean
, that File
- non è stato facile capirlo. Ad esempio, esisteva un metodo getParent()
che restituiva il percorso principale del file corrente come stringa. Ma allo stesso tempo esisteva un metodo getParentFile()
che restituiva la stessa cosa, ma sotto forma di oggetto File
! Ciò è chiaramente ridondante. Pertanto, nell'interfaccia, Path
il metodo getParent()
e altri metodi per lavorare con i file restituiscono semplicemente un oggetto Path
. Non ci sono un sacco di opzioni: tutto è facile e semplice. Quali metodi utili ha Path
? Eccone alcuni ed esempi del loro lavoro:
-
getFileName()
— restituisce il nome del file dal percorso; -
getParent()
— restituisce la directory “genitore” rispetto al percorso corrente (ovvero la directory più in alto nell'albero delle directory); -
getRoot()
— restituisce la directory “root”; cioè quello che si trova in cima all'albero delle directory; -
startsWith()
,endsWith()
- controlla se il percorso inizia/termina con il percorso passato:import java.nio.file.Path; import java.nio.file.Paths; public class Main { public static void main(String[] args) { Path testFilePath = Paths.get("C:\\Users\\Username\\Desktop\\testFile.txt"); Path fileName = testFilePath.getFileName(); System.out.println(fileName); Path parent = testFilePath.getParent(); System.out.println(parent); Path root = testFilePath.getRoot(); System.out.println(root); boolean endWithTxt = testFilePath.endsWith("Desktop\\testFile.txt"); System.out.println(endWithTxt); boolean startsWithLalala = testFilePath.startsWith("lalalala"); System.out.println(startsWithLalala); } }
Uscita console:
testFile.txt
C:\Utenti\Nome utente\Desktop
C:\
true
falsePresta attenzione a come funziona il metodo
endsWith()
. Controlla se il percorso corrente termina con il percorso passato . È sul percorso e non sull'insieme dei personaggi .Confronta i risultati di queste due chiamate:
import java.nio.file.Path; import java.nio.file.Paths; public class Main { public static void main(String[] args) { Path testFilePath = Paths.get("C:\\Users\\Username\\Desktop\\testFile.txt"); System.out.println(testFilePath.endsWith("estFile.txt")); System.out.println(testFilePath.endsWith("Desktop\\testFile.txt")); } }
Uscita console:
falsa
veritàÈ necessario passare al metodo il percorso completo
endsWith()
, e non solo un insieme di caratteri: altrimenti il risultato sarà sempre false , anche se il percorso corrente termina effettivamente con tale sequenza di caratteri (come nel caso di “estFile.txt " nell'esempio sopra).Inoltre, esiste
Path
un gruppo di metodi che semplifica il lavoro con percorsi assoluti (completi) e relativi .
-
boolean isAbsolute()
— restituisce vero se il percorso corrente è assoluto:import java.nio.file.Path; import java.nio.file.Paths; public class Main { public static void main(String[] args) { Path testFilePath = Paths.get("C:\\Users\\Username\\Desktop\\testFile.txt"); System.out.println(testFilePath.isAbsolute()); } }
Uscita console:
VERO
-
Path normalize()
— “normalizza” il percorso corrente, rimuovendo da esso gli elementi non necessari. Potresti sapere che i sistemi operativi più diffusi spesso utilizzano i caratteri "." per indicare i percorsi. (“directory corrente”) e “..” (directory principale). Ad esempio: " ./Pictures/dog.jpg " significa che nella directory in cui ci troviamo adesso, c'è una cartella Immagini e in essa c'è un file "dog.jpg"Quindi eccolo qui. Se il tuo programma ha un percorso che utilizza "." o “..”, il metodo
normalize()
li rimuoverà e otterrà un percorso che non li conterrà:import java.nio.file.Path; import java.nio.file.Paths; public class Main { public static void main(String[] args) { Path path5 = Paths.get("C:\\Users\\Java\\.\\examples"); System.out.println(path5.normalize()); Path path6 = Paths.get("C:\\Users\\Java\\..\\examples"); System.out.println(path6.normalize()); } }
Uscita console:
C:\Utenti\Java\esempi
C:\Utenti\esempi -
Path relativize()
— calcola il percorso relativo tra il percorso attuale e quello superato.Per esempio:
import java.nio.file.Path; import java.nio.file.Paths; public class Main { public static void main(String[] args) { Path testFilePath1 = Paths.get("C:\\Users\\Users\\Users\\Users"); Path testFilePath2 = Paths.get("C:\\Users\\Users\\Users\\Users\\Username\\Desktop\\testFile.txt"); System.out.println(testFilePath1.relativize(testFilePath2)); } }
Uscita console:
Nome utente\Desktop\testFile.txt
Path
è piuttosto ampio. Li potete trovare tutti nella documentazione Oracle . Passiamo alla revisione Files
.
File
Files
- questa è una classe di utilità in cui sono stati spostati i metodi statici della classe File
. Files
- è più o meno uguale a Arrays
o Collections
, funziona solo con i file e non con array e raccolte :) È focalizzato sulla gestione di file e directory. Utilizzando metodi statici Files
, possiamo creare, eliminare e spostare file e directory. Per queste operazioni vengono utilizzati i metodi createFile()
(per le directory - createDirectory()
) move()
e delete()
. Ecco come usarli:
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
public class Main {
public static void main(String[] args) throws IOException {
//file creation
Path testFile1 = Files.createFile(Paths.get("C:\\Users\\Username\\Desktop\\testFile111.txt"));
System.out.println("Was the file created successfully?");
System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testFile111.txt")));
// create directory
Path testDirectory = Files.createDirectory(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory"));
System.out.println("Was the directory successfully created?");
System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory")));
//move file from desktop to testDirectory. You need to move with the name of the file in the folder!
testFile1 = Files.move(testFile1, Paths.get("C:\\Users\\Username\\Desktop\\testDirectory\\testFile111.txt"), REPLACE_EXISTING);
System.out.println("Is our file left on the desktop?");
System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testFile111.txt")));
System.out.println("Has our file been moved to testDirectory?");
System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory\\testFile111.txt")));
//remove file
Files.delete(testFile1);
System.out.println("Does the file still exist?");
System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory\\testFile111.txt")));
}
}
Qui creiamo prima un file (metodo Files.createFile()
) sul desktop, quindi creiamo una cartella lì (metodo Files.createDirectory()
). Successivamente spostiamo il file (metodo Files.move()
) dal desktop in questa nuova cartella e alla fine eliminiamo il file (metodo Files.delete()
). Output della console: il file è stato creato correttamente? true La directory è stata creata correttamente? true Il nostro file è ancora sul desktop? false Il nostro file è stato spostato in testDirectory? true Il file esiste ancora? falso Fai attenzione:Proprio come i metodi dell'interfaccia Path
, molti metodi Files
restituiscono un oggettoPath
. La maggior parte dei metodi di classe Files
accettano anche Path
. Qui il metodo diventerà il tuo fedele assistente Paths.get()
: usalo attivamente. Cos'altro c'è di interessante Files
? Ciò che mancava davvero alla vecchia classe era il metodo ! File
. copy()
Abbiamo parlato di lui all'inizio della conferenza, ora è il momento di incontrarlo!
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
public class Main {
public static void main(String[] args) throws IOException {
//file creation
Path testFile1 = Files.createFile(Paths.get("C:\\Users\\Username\\Desktop\\testFile111.txt"));
System.out.println("Was the file created successfully?");
System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testFile111.txt")));
// create directory
Path testDirectory2 = Files.createDirectory(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory2"));
System.out.println("Was the directory successfully created?");
System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory2")));
//copy the file from the desktop to the directory testDirectory2.
testFile1 = Files.copy(testFile1, Paths.get("C:\\Users\\Username\\Desktop\\testDirectory2\\testFile111.txt"), REPLACE_EXISTING);
System.out.println("Is our file left on the desktop?");
System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testFile111.txt")));
System.out.println("Has our file been copied to testDirectory?");
System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory2\\testFile111.txt")));
}
}
Output della console: il file è stato creato correttamente? true La directory è stata creata correttamente? true Il nostro file è ancora sul desktop? true Il nostro file è stato copiato in testDirectory? true Ora è possibile copiare i file a livello di codice! :) Ma la classe Files
ti consente non solo di gestire i file stessi, ma anche di lavorare con i suoi contenuti. Per scrivere dati in un file, ha un metodo write()
, e per leggere - ben 3:, read()
e su quest'ultimo readAllBytes()
ci readAllLines()
soffermeremo in dettaglio. Perché su di esso? Perché ha un tipo di ritorno molto interessante: List<String>
! Cioè, ci restituisce un elenco di righe nel file. Naturalmente, questo rende molto comodo lavorare con il contenuto, perché l'intero file, riga per riga, può, ad esempio, essere inviato alla console in un ciclo regolare for
:
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import static java.nio.charset.StandardCharsets.UTF_8;
public class Main {
public static void main(String[] args) throws IOException {
List<String> lines = Files.readAllLines(Paths.get("C:\\Users\\Username\\Desktop\\pushkin.txt"), UTF_8);
for (String s: lines) {
System.out.println(s);
}
}
}
Uscita console: Ricordo un momento meraviglioso: sei apparso davanti a me, come una visione fugace, come un genio di pura bellezza. Molto comodamente! :) Questa funzionalità è apparsa in Java 7. In Java 8 è apparsa l'API Stream , che ha aggiunto alcuni elementi di programmazione funzionale a Java. Incluse funzionalità più ricche per lavorare con i file. Immagina di avere un compito: trovare tutte le righe in un file che iniziano con la parola "Come", convertirle in MAIUSCOLO e inviarle alla console. Come sarebbe una soluzione che utilizza una classe Files
in Java 7? Qualcosa come questo:
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import static java.nio.charset.StandardCharsets.UTF_8;
public class Main {
public static void main(String[] args) throws IOException {
List<String> lines = Files.readAllLines(Paths.get("C:\\Users\\Username\\Desktop\\pushkin.txt"), UTF_8);
List<String> result = new ArrayList<>();
for (String s: lines) {
if (s.startsWith("How")) {
String upper = s.toUpperCase();
result.add(upper);
}
}
for (String s: result) {
System.out.println(s);
}
}
}
Uscita console: COME UNA VISIONE DIGIUNATA, COME UN GENIO DI PURA BELLEZZA. Sembra che ce l'abbiamo fatta, ma non credi che per un compito così semplice il nostro codice sia risultato un po'... prolisso? Utilizzando l'API Java 8 Stream la soluzione sembra molto più elegante:
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) throws IOException {
Stream<String> stream = Files.lines(Paths.get("C:\\Users\\Username\\Desktop\\pushkin.txt"));
List<String> result = stream
.filter(line -> line.startsWith("How"))
.map(String::toUpperCase)
.collect(Collectors.toList());
result.forEach(System.out::println);
}
}
Abbiamo ottenuto lo stesso risultato, ma con molto meno codice! Inoltre, non si può dire che abbiamo perso in “leggibilità”. Penso che tu possa facilmente commentare cosa fa questo codice, anche se non hai familiarità con l'API Stream. Ma in sintesi uno Stream è una sequenza di elementi sui quali è possibile svolgere diverse funzioni. Otteniamo l'oggetto Stream dal metodo Files.lines()
e quindi applichiamo 3 funzioni ad esso:
-
Utilizzando il metodo,
filter()
selezioniamo solo quelle righe del file che iniziano con "Come". -
Esaminiamo tutte le righe selezionate utilizzando il metodo
map()
e riduciamo ciascuna di esse in MAIUSCOLO. -
Combiniamo tutte le righe risultanti
List
utilizzando il filecollect()
.
Files.walkFileTree()
. Ecco cosa dobbiamo fare. Innanzitutto, abbiamo bisogno di FileVisitor
. FileVisitor
è un'interfaccia speciale che descrive tutti i metodi per attraversare l'albero dei file. Nello specifico, inseriremo la logica per leggere il contenuto del file e verificare se contiene il testo di cui abbiamo bisogno. Ecco come apparirà il nostro FileVisitor
:
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.List;
public class MyFileVisitor extends SimpleFileVisitor<Path> {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
List<String> lines = Files.readAllLines(file);
for (String s: lines) {
if (s.contains("This is the file we need")) {
System.out.println("Required file found!");
System.out.println(file.toAbsolutePath());
break;
}
}
return FileVisitResult.CONTINUE;
}
}
In questo caso, la nostra classe eredita da SimpleFileVisitor
. Questa è una classe che implementa FileVisitor
, in cui è necessario sovrascrivere solo un metodo: visitFile()
. Qui descriviamo cosa è necessario fare con ciascun file in ciascuna directory. Se hai bisogno di una logica di attraversamento più complessa, dovresti scrivere la tua implementazione FileVisitor
. Lì dovrai implementare altri 3 metodi:
-
preVisitDirectory()
— logica che deve essere eseguita prima di accedere alla cartella; -
visitFileFailed()
— cosa fare se l'accesso al file è impossibile (nessun accesso o altri motivi); -
postVisitDirectory()
— la logica che deve essere eseguita dopo l'accesso alla cartella.
SimpleFileVisitor
. La logica all'interno del metodo visitFile()
è abbastanza semplice: leggere tutte le righe del file, verificare se contengono il contenuto di cui abbiamo bisogno e, in tal caso, stampare il percorso assoluto della console. L'unica riga che potrebbe darti problemi è questa:
return FileVisitResult.CONTINUE;
In effetti, tutto è semplice. Qui descriviamo semplicemente cosa dovrebbe fare il programma dopo aver inserito il file e aver completato tutte le operazioni necessarie. Nel nostro caso, dobbiamo continuare ad attraversare l'albero, quindi scegliamo l'opzione CONTINUE
. Ma noi, ad esempio, potremmo avere un altro compito: trovare non tutti i file che contengono "Questo è il file di cui abbiamo bisogno", ma solo uno di questi file . Successivamente è necessario terminare il programma. In questo caso, il nostro codice sarebbe esattamente lo stesso, ma invece di break; volevo:
return FileVisitResult.TERMINATE;
Bene, eseguiamo il nostro codice e vediamo se funziona.
import java.io.IOException;
import java.nio.file.*;
public class Main {
public static void main(String[] args) throws IOException {
Files.walkFileTree(Paths.get("C:\\Users\\Username\\Desktop\\testFolder"), new MyFileVisitor());
}
}
Output della console: il file richiesto è stato trovato! C:\Users\Username\Desktop\testFolder\FileWeNeed1.txt Il file richiesto è stato trovato! C:\Users\Username\Desktop\testFolder\level1-a\level2-aa\FileWeNeed2.txt Il file richiesto è stato trovato! C:\Users\Username\Desktop\testFolder\level1-b\level2-bb\FileWeNeed3.txt Ottimo, ce l'abbiamo fatta! :) Se vuoi saperne di più walkFileTree()
, ti consiglio questo articolo . Puoi anche completare una piccola attività: sostituirla SimpleFileVisitor
con una normale FileVisitor
, implementare tutti e 4 i metodi e trovare uno scopo per questo programma. Ad esempio, puoi scrivere un programma che registrerà tutte le tue azioni: visualizzerà il nome di un file o di una cartella nella console prima/dopo averli inseriti. Questo è tutto: ci vediamo più tardi! :)
GO TO FULL VERSION