CodeGym/Java-blogg/Tilfeldig/Java-filer, bane
John Squirrels
Nivå
San Francisco

Java-filer, bane

Publisert i gruppen
Hei! I dag skal vi snakke om å jobbe med filer og kataloger. Du vet allerede hvordan du administrerer filinnhold: vi har dedikert mange leksjoner til dette :) Jeg tror du synes det er lett å huske noen få klasser brukt til disse formålene. I dagens leksjon skal vi snakke spesifikt om filbehandling: opprettelse, gi nytt navn osv. Før Java 7 ble alle slike operasjoner utført ved hjelp av File- klassen. Du kan lese om det her . Men i Java 7 bestemte språkskaperne seg for å endre hvordan vi jobber med filer og kataloger. Dette skjedde fordi File -klassen hadde flere ulemper. For eksempel hadde den ikke copy()- metoden, som ville la deg kopiere en fil fra ett sted til et annet (en tilsynelatende essensiell evne). i tilleggFilklassen hadde ganske mange metoder som returnerte boolske verdier. Når det er en feil, returnerer en slik metode usann. Det gir ikke et unntak, noe som gjør det svært vanskelig å identifisere feil og diagnostisere årsakene deres. I stedet for den enkle File- klassen dukket det opp 3 klasser: Paths , Path , og Files . Vel, for å være presis, er Path et grensesnitt, ikke en klasse. La oss finne ut hvordan de skiller seg fra hverandre og hvorfor vi trenger hver av dem. La oss starte med det enkleste: Stier .

stier

Paths er en veldig enkel klasse med en enkelt statisk metode: get() . Den ble opprettet utelukkende for å hente et Path- objekt fra den passerte strengen eller URI. Den har ingen annen funksjonalitet. Her er et eksempel på det på jobb:
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");
   }
}
Ikke den mest komplekse klassen, ikke sant? :) Vel, vi har også denne Path- typen. La oss finne ut hva Path er og hvorfor det er nødvendig :)

Sti

Path , stort sett, er en redesignet analog av File- klassen. Det er mye enklere å jobbe med enn File . Først ble mange verktøy (statiske) metoder tatt ut og flyttet til klassen Files . For det andre ble det pålagt ordre på returverdiene til metodene til Path- grensesnittet. I File- klassen returnerte metoder enten en String , eller en boolean , eller en File . Det var ikke lett å finne ut av det. For eksempel var det en getParent() -metode som returnerte en streng som representerer den overordnede banen til gjeldende fil. Men det var også engetParentFile() -metoden, som returnerte det samme, men i form av et File- objekt! Dette er helt klart overflødig. Følgelig, i Path- grensesnittet,returnerer getParent() -metoden og andre metoder for å jobbe med filer ganske enkelt et Path- objekt. Ingen haug med alternativer - alt er enkelt og enkelt. Hva er noen av de nyttige metodene som Path har? Her er noen av dem og eksempler på hvordan de fungerer:
  • getFileName() : returnerer filnavnet fra banen;

  • getParent() : returnerer "overordnet"-katalogen til gjeldende bane (med andre ord, katalogen som ligger rett ovenfor i katalogtreet);

  • getRoot() : returnerer "root"-katalogen, dvs. katalogen øverst i katalogtreet;

  • startsWith() , endsWith() : sjekk om banen starter/slutter med den passerte banen:

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

    Konsoll utgang:

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

    Vær oppmerksom på hvordan endsWith()- metoden fungerer. Den sjekker om den gjeldende banen slutter med den passerte banen . Nærmere bestemt om det er i banen , ikke i den passerte strengen .

    Sammenlign resultatene av disse to samtalene:

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

    Konsoll utgang:

    false
    true

    EndsWith () -metoden må sendes en ekte bane, ikke bare et sett med tegn: ellers vil resultatet alltid være usant, selv om den gjeldende banen virkelig ender med den sekvensen av tegn (som tilfellet er med "estFile.txt" " i eksemplet ovenfor).

    I tillegg har Path en gruppe metoder som forenkler arbeidet med absolutte (fulle) og relative baner .

La oss se på disse metodene:
  • boolean isAbsolute() returnerer sann hvis gjeldende bane er absolutt:

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

    Konsoll utgang:

    true
  • Path normalize() : "normaliserer" den gjeldende banen, fjerner unødvendige elementer fra den. Du vet kanskje at i populære operativsystemer symbolene "." (nåværende katalog) og ".." (overordnet katalog) brukes ofte til å angi stier. For eksempel betyr " ./Pictures/dog.jpg " at den gjeldende katalogen har en "Pictures"-mappe, som igjen inneholder en "dog.jpg"-fil.

    Se her. Hvis en bane bruker "." eller ".." vises i programmet ditt, vil normalize() -metoden fjerne dem og produsere en bane som ikke inneholder dem:

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

    Konsoll utgang:

    C:\Users\Java\examples
    C:\Users\examples
  • Path relativize() : beregner den relative banen mellom gjeldende og passerte banen.

    For eksempel:

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

    Konsoll utgang:

    Username\Desktop\testFile.txt

Den komplette listen over Path -metoder er ganske lang. Du finner dem alle i Oracle-dokumentasjonen . Nå går vi videre til å vurdere filer .

Filer

Files er en verktøyklasse som inneholder de statiske metodene tatt ut av File- klassen. Filer kan sammenlignes med Arrays eller Collections . Forskjellen er at det fungerer med filer, ikke arrays eller samlinger :) Den fokuserer på å administrere filer og kataloger. Ved å bruke de statiske metodene til Files -klassen kan vi opprette, slette og flytte filer og kataloger. Disse operasjonene utføres ved å bruke metodene createFile() (for kataloger, createDirectory() ), move() og delete()- metodene. Slik bruker du dem:
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")));
   }
}
Her lager vi først en fil ( Files.createFile() -metoden) på skrivebordet. Deretter oppretter vi en mappe på samme sted ( Files.createDirectory() -metoden). Etter det flytter vi filen ( Files.move() -metoden) fra skrivebordet til denne nye mappen, og til slutt sletter vi filen ( Files.delete() -metoden). Konsoll utgang:
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
Merk:som metodene i grensesnittet Path, returnerer mange metoder iFilesPath klassen et objekt. De fleste metodene i Filesklassen tar også Pathobjekter som input. Her Paths.get()vil metoden være din trofaste assistent - bruk den godt. Hva annet er interessant i Files? Det den gamle Fileklassen virkelig manglet er en copy()metode! Vi snakket om det i begynnelsen av denne leksjonen. Nå er det på tide å møte det!
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")));
   }
}
Konsoll utgang:
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
Nå vet du hvordan du kopierer filer programmatisk! :) Selvfølgelig Fileslar klassen deg ikke bare administrere en fil selv, men også jobbe med innholdet. Den har write()metoden for å skrive data til en fil, og alle 3 metoder for å lese data: read(), readAllBytes(), og readAllLines() Vi vil dvele i detalj ved den siste. Hvorfor den? Fordi den har en veldig interessant returtype: List<String>! Det vil si at den returnerer oss en liste over alle linjene i filen. Dette gjør det selvfølgelig veldig praktisk å jobbe med filinnholdet, fordi hele filen, linje for linje, kan for eksempel vises på konsollen ved hjelp av en vanlig forsløyfe:
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);
       }
   }
}
Konsoll utgang:
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 praktisk! :) Denne muligheten dukket opp i Java 7. Stream API dukket opp i Java 8. Den legger til noen elementer av funksjonell programmering til Java. Inkludert rikere filhåndteringsmuligheter. Tenk deg at vi har følgende oppgave: Finn alle linjene som begynner med ordet "Som", konverter dem til STORE BOKSTAVER, og vis dem på konsollen. Hvordan vil en løsning med Filesklassen se ut i Java 7? Noe sånt som dette:
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);
       }
   }
}
Konsoll utgang:
AS THOUGH A BRIEF AND FLEETING OMEN,
PURE PHANTOM IN ENCHANTING LIGHT.
Oppdraget fullført, men tror du ikke at koden vår for en så enkel oppgave viste seg å være litt... detaljert? Ved å bruke Java 8s Stream API ser løsningen mye mer elegant ut:
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);
   }
}
Vi oppnådde samme resultat, men med mye mindre kode! Dessuten kan ingen si at vi har mistet «lesbarheten». Jeg tror du enkelt kan kommentere hva denne koden gjør, selv uten å være kjent med Stream API. Kort sagt, en Stream er en sekvens av elementer, som du kan utføre ulike operasjoner over. Vi får et Stream-objekt fra Files.lines()metoden, og bruker deretter 3 funksjoner på det:
  1. Vi bruker filter()metoden til å velge bare de linjene fra filen som begynner med "Som".

  2. Vi går gjennom alle de valgte linjene ved hjelp av map()metoden og konverterer hver av dem til STORE BOKSTAVER.

  3. Vi bruker collect()metoden til å samle alle de mottatte linjene til en List.

Vi får samme utgang:
AS THOUGH A BRIEF AND FLEETING OMEN,
PURE PHANTOM IN ENCHANTING LIGHT.
La oss nå gå tilbake til vårt brød og smør, det vil si filer :) Den siste muligheten vi vil vurdere i dag er å gå gjennom et filtre . I moderne operativsystemer ser filstrukturen oftest ut som et tre: den har en rot og det er grener, som kan ha andre grener osv. Roten og grenene er kataloger. For eksempel kan katalogen " С:// " være roten. Den inkluderer to grener: " C://Nedlastinger " og " C://Brukere ". Hver av disse grenene har to grener: " C://Downloads/Pictures ", " C://Downloads/Video ", " C://Users/JohnSmith ", " C://Users/Pudge2005". Og disse grenene har igjen andre grener osv. og det er derfor vi kaller det et tre. På Linux er strukturen lik, men /-katalogen er roten. Tenk deg nå at vi må starte ved Filer, bane - 2rotkatalogen , gå gjennom alle mappene og undermappene, og finn filer som har noe bestemt innhold. Vi vil søke etter filer som inneholder linjen "Dette er filen vi trenger!" Vi tar mappen "testFolder", som er på skrivebordet, som rotkatalogen. Her er innholdet: Filer, bane - 3Mappene nivå1-a og nivå1-b inneholder også mapper: Filer, bane - 4Filer, bane - 5Det er ingen mapper i disse "mappene på andre nivå", kun individuelle filer: Filer, bane - 6Filer, bane - 7De 3 filene med innholdet vi trenger er bevisst gitt forklarende navn: FileWeNeed1.txt, FileWeNeed2.txt, FileWeNeed3.txt. Dette er nettopp filene vi trenger å finne ved hjelp av Java. Hvordan gjør vi dette? En veldig kraftig metode for å krysse et filtre kommer til vår hjelp: Files.walkFileTree (). Her er hva vi må gjøre. Først trenger vi en FileVisitor. FileVisitorer et spesielt grensesnitt, der metodene for å krysse et filtre er beskrevet. Det er spesielt der vi legger logikken for å lese innholdet i en fil og sjekke om den inneholder teksten vi trenger. Slik FileVisitorser vår ut:
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;
   }
}
I dette tilfellet arver klassen vår SimpleFileVisitor. Dette er en klasse som implementerer FileVisitor, der vi bare trenger å overstyre én metode: visitFile(). Her definerer vi hva som må gjøres med hver fil i hver katalog. Hvis du trenger mer kompleks logikk for å krysse filstrukturen, bør du skrive din egen implementering av FileVisitor. Du må implementere 3 flere metoder i den klassen:
  • preVisitDirectory(): logikken som skal utføres før du går inn i en mappe;

  • visitFileFailed(): logikken for å utføre hvis en fil ikke kan besøkes (ingen tilgang, eller av andre grunner);

  • postVisitDirectory(): logikken som skal utføres etter å gå inn i en mappe.

Vi trenger ingen slik logikk utført, så vi har det bra med SimpleFileVisitor. Logikken i visitFile()metoden er ganske enkel: les alle linjene i filen, sjekk om de inneholder innholdet vi trenger, og i så fall skriv ut den absolutte banen på konsollen. Den eneste linjen som kan forårsake problemer er denne:
return FileVisitResult.CONTINUE;
Egentlig er dette veldig enkelt. Her beskriver vi bare hva programmet skal gjøre etter at filen er besøkt og alle nødvendige operasjoner er utført. I vårt tilfelle ønsker vi å fortsette å krysse treet, så vi velger alternativet CONTINUE. Men alternativt kan vi ha et annet mål: i stedet for å finne alle filene som inneholder "Dette er filen vi trenger", finn bare én slik fil . Etter det skal programmet avsluttes. I dette tilfellet vil koden vår se nøyaktig lik ut, men i stedet for pause vil det være:
return FileVisitResult.TERMINATE;
Vel, la oss kjøre koden vår og se om den fungerer.
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());
   }
}
Konsoll utgang:
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
Utmerket! Det funket! :) Du kan også akseptere denne lille utfordringen: erstatt SimpleFileVisitormed en vanlig FileVisitor, overstyr alle 4 metodene, og kom opp med ditt eget formål med programmet. Du kan for eksempel skrive et program som logger alle handlingene: vis navnet på filen eller mappen før eller etter du har skrevet dem inn. Det er alt for nå. Ser deg snart! :)
Kommentarer
  • Populær
  • Ny
  • Gammel
Du må være pålogget for å legge igjen en kommentar
Denne siden har ingen kommentarer ennå