CodeGym /Blog Java /Aleatoriu /Fișiere Java, cale
John Squirrels
Nivel
San Francisco

Fișiere Java, cale

Publicat în grup
Bună! Astăzi vom vorbi despre lucrul cu fișiere și directoare. Știți deja cum să gestionați conținutul fișierelor: am dedicat o mulțime de lecții acestui lucru :) Cred că vă este ușor să vă amintiți câteva clase folosite în aceste scopuri. În lecția de astăzi, vom vorbi în mod specific despre managementul fișierelor: crearea, redenumirea etc. Înainte de Java 7, toate astfel de operațiuni erau efectuate folosind clasa File . Puteți citi despre asta aici . Dar în Java 7, creatorii limbajului au decis să schimbe modul în care lucrăm cu fișierele și directoarele. Acest lucru s-a întâmplat deoarece clasa File avea mai multe dezavantaje. De exemplu, nu avea metoda copy() , care vă permitea să copiați un fișier dintr-o locație în alta (o abilitate aparent esențială). In plusClasa de fișiere avea destul de multe metode care returnau valori booleene . Când există o eroare, o astfel de metodă returnează false. Nu face excepție, ceea ce face foarte dificilă identificarea erorilor și diagnosticarea cauzelor acestora. În locul clasei unice File au apărut 3 clase: Paths , Path , and Files . Ei bine, pentru a fi mai precis, Path este o interfață, nu o clasă. Să ne dăm seama cum diferă ele unele de altele și de ce avem nevoie de fiecare dintre ele. Să începem cu cel mai simplu: Căi .

Cărări

Paths este o clasă foarte simplă cu o singură metodă statică: get() . A fost creat doar pentru a obține un obiect Path din șirul sau URI-ul transmis. Nu are altă funcționalitate. Iată un exemplu la locul de muncă:

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");
   }
}
Nu este cea mai complexă clasă, nu? :) Ei bine, avem și acest tip de cale . Să ne dăm seama ce este Calea și de ce este nevoie de ea :)

cale

Calea , în general, este un analog reproiectat al clasei File . Este mult mai ușor de lucrat decât cu File . Mai întâi , multe metode utilitare (statice) au fost eliminate și mutate în clasa Fișiere . În al doilea rând , ordinea a fost impusă asupra valorilor returnate ale metodelor interfeței Path . În clasa File , metodele au returnat fie un String , fie un boolean , fie un File . Nu a fost ușor să-ți dai seama. De exemplu, a existat o metodă getParent() care a returnat un șir reprezentând calea părinte a fișierului curent. Dar a existat și ogetParentFile() , care a returnat același lucru, dar sub forma unui obiect File ! Acest lucru este în mod clar redundant. În consecință, în interfața Path , metoda getParent() și alte metode de lucru cu fișiere returnează pur și simplu un obiect Path . Fără o grămadă de opțiuni - totul este ușor și simplu. Care sunt unele dintre metodele utile pe care le are Path ? Iată câteva dintre ele și exemple despre cum funcționează:
  • getFileName() : returnează numele fișierului din cale;

  • getParent() : returnează directorul „părinte” al căii curente (cu alte cuvinte, directorul situat imediat deasupra în arborele de directoare);

  • getRoot() : returnează directorul „rădăcină”, adică directorul din partea de sus a arborelui de directoare;

  • startsWith() , endsWith() : verificați dacă calea începe/se termină cu calea transmisă:

    
    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);
       }
    }
    

    Ieșire din consolă:

    
    testFile.txt
    C:\Users\Username\Desktop
    C:\
    true
    false
    

    Acordați atenție modului în care funcționează metoda endsWith() . Verifică dacă calea curentă se termină cu calea trecută . Mai exact, dacă este în cale , nu în șirul transmis .

    Comparați rezultatele acestor două apeluri:

    
    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"));
       }
    }
    

    Ieșire din consolă:

    
    false
    true
    

    Metodei endsWith() trebuie să primească o cale autentică, nu doar un set de caractere: în caz contrar, rezultatul va fi întotdeauna fals, chiar dacă calea curentă se termină într-adevăr cu acea secvență de caractere (cum este cazul „estFile.txt " în exemplul de mai sus).

    În plus, Path are un grup de metode care simplifică lucrul cu căi absolute (complete) și relative .

Să ne uităm la aceste metode:
  • boolean isAbsolute() returnează adevărat dacă calea curentă este absolută:

    
    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());
       }
    }
    

    Ieșire din consolă:

    
    true
    
  • Path normalize() : „normalizează” calea curentă, eliminând elementele inutile din ea. Poate știți că în sistemele de operare populare simbolurile "." (directorul curent) și „..” (directorul părinte) sunt adesea folosite pentru a desemna căi. De exemplu, „ ./Pictures/dog.jpg ” înseamnă că directorul curent are un folder „Pictures”, care la rândul său conține un fișier „dog.jpg”.

    Uite aici. Dacă o cale care utilizează „." sau „..” apare în programul dvs., metoda normalize() le va elimina și va produce o cale care nu le conține:

    
    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());
       }
    }
    

    Ieșire din consolă:

    
    C:\Users\Java\examples
    C:\Users\examples
    
  • Path relativize() : calculează calea relativă dintre calea curentă și cea trecută.

    De exemplu:

    
    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));
       }
    }
    

    Ieșire din consolă:

    
    Username\Desktop\testFile.txt
    

Lista completă a metodelor Path este destul de lungă. Le puteți găsi pe toate în documentația Oracle . Acum vom trece la considerarea Fișierelor .

Fișiere

Files este o clasă de utilitate care deține metodele statice scoase din clasa File . Files este comparabil cu Arrays sau Collections . Diferența este că funcționează cu fișiere, nu cu matrice sau colecții :) Se concentrează pe gestionarea fișierelor și directoarelor. Folosind metodele statice ale clasei Files , putem crea, șterge și muta fișiere și directoare. Aceste operațiuni sunt efectuate folosind metodele createFile() (pentru directoare, createDirectory() ), move() și delete() . Iată cum să le folosiți:

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 {

       // Create a file
       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 a directory
       Path testDirectory = Files.createDirectory(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory"));
       System.out.println("Was the directory created successfully?");
       System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory")));

       // Move the file from the desktop to the testDirectory directory. When you move a folder, you need to indicate its name in the folder!
       testFile1 = Files.move(testFile1, Paths.get("C:\\Users\\Username\\Desktop\\testDirectory\\testFile111.txt"), REPLACE_EXISTING);

       System.out.println("Did our file remain 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")));

       // Delete a 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")));
   }
}
Aici creăm mai întâi un fișier ( metoda Files.createFile() ) pe desktop. Apoi creăm un folder în aceeași locație ( metoda Files.createDirectory() ). După aceea, mutăm fișierul ( metoda Files.move() ) de pe desktop în acest nou folder și, în final, ștergem fișierul ( metoda Files.delete() ). Ieșire din consolă:

Was the file created successfully? 
true 
Was the directory created successfully? 
true
Did our file remain on the desktop? 
false 
Has our file been moved to testDirectory? 
true 
Does the file still exist? 
false
Notă:ca și metodele interfeței Path, multe metode ale Filesclasei returnează unPath obiect. Cele mai multe dintre metodele clasei Filesiau și Pathobiecte ca intrări. Aici Paths.get()metoda va fi asistentul tău credincios - folosește-o bine. Ce altceva este interesant Files? Ceea ce îi lipsea cu adevărat vechii Fileclase este o copy()metodă! Am vorbit despre asta la începutul acestei lecții. Acum este timpul să-l întâlnim!

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 {

       // Create a file
       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 a directory
       Path testDirectory2 = Files.createDirectory(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory2"));
       System.out.println("Was the directory created successfully?");
       System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory2")));

       // Copy the file from the desktop to the testDirectory2 directory.
       testFile1 = Files.copy(testFile1, Paths.get("C:\\Users\\Username\\Desktop\\testDirectory2\\testFile111.txt"), REPLACE_EXISTING);

       System.out.println("Did our file remain on the desktop?");
       System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testFile111.txt")));

       System.out.println("Was our file copied to testDirectory?");
       System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory2\\testFile111.txt")));
   }
}
Ieșire din consolă:

Was the file created successfully? 
true 
Was the directory created successfully? 
true 
Did our file remain on the desktop? 
true 
Was our file copied to testDirectory? 
true
Acum știți cum să copiați fișierele în mod programatic! :) Desigur, Filesclasa vă permite nu numai să gestionați un fișier în sine, ci și să lucrați cu conținutul acestuia. Are write()metoda de scriere a datelor într-un fișier și toate cele 3 metode de citire a datelor: read(), readAllBytes(), și readAllLines() Ne vom opri în detaliu asupra ultimei. De ce acela? Pentru că are un tip de returnare foarte interesant: List<String>! Adică, ne returnează o listă cu toate liniile din fișier. Desigur, acest lucru face foarte convenabil să lucrezi cu conținutul fișierului, deoarece întregul fișier, linie cu linie, poate fi, de exemplu, afișat pe consolă folosind o buclă obișnuită 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);
       }
   }
}
Ieșire din consolă:

I still recall the wondrous moment: 
When you appeared before my sight, 
As though a brief and fleeting omen, 
Pure phantom in enchanting light.
Super convenabil! :) Această abilitate a apărut în Java 7. Stream API a apărut în Java 8. Adaugă câteva elemente de programare funcțională la Java. Inclusiv capabilități mai bogate de gestionare a fișierelor. Imaginați-vă că avem următoarea sarcină: găsiți toate liniile care încep cu cuvântul „As”, convertiți-le în MAJUSCULE și afișați-le pe consolă. Cum ar arăta o soluție care folosește Filesclasa în Java 7? Ceva de genul:

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("As")) {
               String upper = s.toUpperCase();
               result.add(upper);
           }
       }

       for (String s: result) {
           System.out.println(s);
       }
   }
}
Ieșire din consolă:

AS THOUGH A BRIEF AND FLEETING OMEN, 
PURE PHANTOM IN ENCHANTING LIGHT.
Misiune îndeplinită, dar nu crezi că pentru o sarcină atât de simplă codul nostru s-a dovedit a fi puțin... verbos? Folosind API-ul Stream din Java 8, soluția arată mult mai elegantă:

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("As"))
               .map(String::toUpperCase)
               .collect(Collectors.toList());
       result.forEach(System.out::println);
   }
}
Am obținut același rezultat, dar cu mult mai puțin cod! Mai mult, nimeni nu poate spune că am pierdut „lizibilitatea”. Cred că puteți comenta cu ușurință ce face acest cod, chiar și fără a fi familiarizat cu API-ul Stream. Pe scurt, un Stream este o secvență de elemente, peste care puteți efectua diverse operații. Obținem un obiect Stream din Files.lines()metodă și apoi îi aplicăm 3 funcții:
  1. Folosim filter()metoda pentru a selecta doar acele linii din fișier care încep cu „As”.

  2. Trecem prin toate liniile selectate folosind map()metoda și convertim fiecare dintre ele în MAJUSCULĂ.

  3. Folosim collect()metoda pentru a aduna toate liniile primite într-un List.

Obținem aceeași ieșire:

AS THOUGH A BRIEF AND FLEETING OMEN, 
PURE PHANTOM IN ENCHANTING LIGHT.
Acum să revenim la pâinea și untul nostru, adică fișierele :) Ultima capacitate pe care o vom lua în considerare astăzi este mersul printr-un arbore de fișiere . În sistemele de operare moderne, structura fișierelor arată cel mai adesea ca un arbore: are o rădăcină și există ramuri, care pot avea alte ramuri etc. Rădăcina și ramurile sunt directoare. De exemplu, directorul „ С:// ” poate fi rădăcină. Include două ramuri: „ C://Downloads ” și „ C://Users ”. Fiecare dintre aceste ramuri are două ramuri: " C://Downloads/Pictures ", " C://Downloads/Video ", " C://Users/JohnSmith ", " C://Users/Pudge2005„. Și aceste ramuri au, la rândul lor, alte ramuri etc. și de aceea îi spunem arbore. Pe Linux, structura este similară, dar directorul / este rădăcină .Fișiere, Cale - 2 Acum imaginați-vă că trebuie să începem de la directorul rădăcină. , parcurgeți toate folderele și subfolderele sale și găsiți fișiere care au un anumit conținut. Vom căuta fișiere care conțin linia „Acesta este fișierul de care avem nevoie!” Vom lua folderul „testFolder”, care este pe desktop, ca director rădăcină.Iată conținutul acestuia: Fișiere, Cale - 3folderele level1-a și level1-b conțin și foldere: Fișiere, Cale - 4Fișiere, cale - 5nu există foldere în aceste „directoare de al doilea nivel”, doar fișiere individuale: Fișiere, cale - 6Fișiere, Cale - 7Cele 3 fișiere cu conținutul de care avem nevoie primesc în mod deliberat nume explicative: FileWeNeed1.txt, FileWeNeed2.txt, FileWeNeed3.txt. Acestea sunt exact fișierele pe care trebuie să le găsim folosind Java. Cum facem asta? O metodă foarte puternică de parcurgere a unui arbore de fișiere ne vine în ajutor: Files.walkFileTree (). Iată ce trebuie să facem. În primul rând, avem nevoie de un FileVisitor. FileVisitoreste o interfață specială, în care sunt descrise metodele de parcurgere a unui arbore de fișiere. În special, acolo vom pune logica pentru citirea conținutului unui fișier și verificarea dacă acesta conține textul de care avem nevoie. Iată cum FileVisitorarată:

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("We found a file we need!");
               System.out.println(file.toAbsolutePath());
               break;
           }
       }

       return FileVisitResult.CONTINUE;
   }
}
În acest caz, clasa noastră moștenește SimpleFileVisitor. Aceasta este o clasă care implementează FileVisitor, în care trebuie să suprascriem doar o singură metodă: visitFile(). Aici definim ce trebuie făcut cu fiecare fișier din fiecare director. Dacă aveți nevoie de o logică mai complexă pentru a parcurge structura fișierului, ar trebui să scrieți propria implementare a FileVisitor. Ar trebui să implementați încă 3 metode în acea clasă:
  • preVisitDirectory(): logica de executat înainte de a intra într-un folder;

  • visitFileFailed(): logica de executat dacă un fișier nu poate fi vizitat (fără acces, sau din alte motive);

  • postVisitDirectory(): logica de executat după intrarea într-un folder.

Nu avem nevoie de o astfel de logică executată, așa că suntem bine cu SimpleFileVisitor. Logica din interiorul visitFile()metodei este destul de simplă: citiți toate liniile din fișier, verificați dacă acestea conțin conținutul de care avem nevoie și, dacă da, imprimați calea absolută pe consolă. Singura linie care vă poate cauza dificultăți este aceasta:

return FileVisitResult.CONTINUE;
De fapt, acest lucru este foarte simplu. Aici descriem pur și simplu ce ar trebui să facă programul după ce fișierul este vizitat și au fost efectuate toate operațiunile necesare. În cazul nostru, dorim să continuăm să traversăm arborele, așa că alegem opțiunea CONTINUE. Dar, alternativ, am putea avea un obiectiv diferit: în loc să găsim toate fișierele care conțin „Acesta este fișierul de care avem nevoie”, găsiți doar un astfel de fișier . După aceea, programul ar trebui să se încheie. În acest caz, codul nostru ar arăta exact la fel, dar în loc de întrerupere ar fi:

return FileVisitResult.TERMINATE;
Ei bine, hai să rulăm codul nostru și să vedem dacă funcționează.

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());
   }
}
Ieșire din consolă:

We found a file we need! 
C:\Users\Username\Desktop\testFolder\FileWeNeed1.txt 
We found a file we need! 
C:\Users\Username\Desktop\testFolder\level1-a\level2-a-a\FileWeNeed2.txt 
We found a file we need! 
C:\Users\Username\Desktop\testFolder\level1-b\level2-b-b\FileWeNeed3.txt
Excelent! A mers! :) Ați putea accepta și această mică provocare: înlocuiți SimpleFileVisitorcu un obișnuit FileVisitor, suprascrieți toate cele 4 metode și găsiți propriul scop pentru program. De exemplu, puteți scrie un program care înregistrează toate acțiunile sale: afișați numele fișierului sau folderului înainte sau după introducerea acestora. Asta este tot pentru acum. Pe curând! :)
Comentarii
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION