stigar
Paths är en mycket enkel klass med en enda statisk metod: get() . Det skapades enbart för att hämta ett sökvägsobjekt från den passerade strängen eller URI. Den har ingen annan funktion. Här är ett exempel på det på jobbet:
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");
}
}
Inte den mest komplexa klassen, eller hur? :) Tja, vi har också den här typen Path . Låt oss ta reda på vad Path är och varför det behövs :)
Väg
Path är i stort sett en omdesignad analog av File -klassen. Det är mycket lättare att arbeta med än File . Först togs många verktyg (statiska) metoder ut och flyttades till klassen Files . För det andra ålades ordning på returvärdena för metoderna för Path -gränssnittet. I klassen File returnerade metoder antingen en String , eller en boolean , eller en File . Det var inte lätt att lista ut det. Det fanns till exempel en getParent() -metod som returnerade en sträng som representerar den överordnade sökvägen för den aktuella filen. Men det fanns också engetParentFile() -metoden, som returnerade samma sak men i form av ett File -objekt! Detta är helt klart överflödigt. Följaktligen returnerar getParent()-metoden och andra metoder för att arbeta med filer isökvägsgränssnittet helt enkelt ett sökvägsobjekt . Ingen hög med alternativ - allt är enkelt och enkelt. Vilka är några av de användbara metoderna som Path har? Här är några av dem och exempel på hur de fungerar:-
getFileName() : returnerar filnamnet från sökvägen;
-
getParent() : returnerar "förälder"-katalogen för den aktuella sökvägen (med andra ord, katalogen som finns omedelbart ovanför i katalogträdet);
-
getRoot() : returnerar "root"-katalogen, dvs katalogen högst upp i katalogträdet;
-
startsWith() , endsWith() : kontrollera om sökvägen börjar/slutar med den passerade sökvägen:
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); } }
Konsolutgång:
testFile.txt C:\Users\Username\Desktop C:\ true false
Var uppmärksam på hur endsWith() -metoden fungerar. Den kontrollerar om den aktuella sökvägen slutar med den passerade sökvägen . Specifikt om det är i sökvägen , inte i den passerade strängen .
Jämför resultaten av dessa två samtal:
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")); } }
Konsolutgång:
false true
EndsWith () -metoden måste skickas en äkta sökväg, inte bara en uppsättning tecken: annars kommer resultatet alltid att vara falskt, även om den aktuella sökvägen verkligen slutar med den teckensekvensen (som är fallet med "estFile.txt" " i exemplet ovan).
Dessutom har Path en grupp metoder som förenklar arbetet med absoluta (fullständiga) och relativa vägar .
-
boolean isAbsolute() returnerar true om den aktuella sökvägen är 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()); } }
Konsolutgång:
true
-
Path normalize() : "normaliserar" den aktuella sökvägen och tar bort onödiga element från den. Du kanske vet att i populära operativsystem symbolerna "." (nuvarande katalog) och ".." (överordnad katalog) används ofta för att ange sökvägar. Till exempel betyder " ./Pictures/dog.jpg " att den aktuella katalogen har en "Pictures"-mapp, som i sin tur innehåller en "dog.jpg"-fil.
Titta här. Om en sökväg använder "." eller ".." visas i ditt program, kommer normalize() -metoden att ta bort dem och skapa en sökväg som inte innehåller 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()); } }
Konsolutgång:
C:\Users\Java\examples C:\Users\examples
-
Path relativize() : beräknar den relativa vägen mellan den nuvarande och den passerade vägen.
Till exempel:
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)); } }
Konsolutgång:
Username\Desktop\testFile.txt
Filer
Files är en verktygsklass som innehåller de statiska metoder som tagits ut urklassen File . Filer är jämförbara med Arrays eller Collections . Skillnaden är att det fungerar med filer, inte arrayer eller samlingar :) Den fokuserar på att hantera filer och kataloger. Genom att använda de statiska metoderna i klassen Files kan vi skapa, ta bort och flytta filer och kataloger. Dessa operationer utförs med metoderna createFile() (för kataloger, createDirectory() ), move() och delete()- metoderna. Så här använder 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")));
}
}
Här skapar vi först en fil ( metoden Files.createFile()) på skrivbordet. Sedan skapar vi en mapp på samma plats ( metoden Files.createDirectory()) . Efter det flyttar vi filen ( Files.move() -metoden) från skrivbordet till den här nya mappen, och slutligen tar vi bort filen ( Files.delete() -metoden). Konsolutgång:
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
Notera:liksom metoderna i Path
gränssnittet returnerar många metoder iFiles
Path
klassen ett objekt. De flesta av klassens metoder Files
tar också Path
objekt som indata. Här Paths.get()
kommer metoden att vara din trogna assistent - använd den väl. Vad är mer intressant i Files
? Vad den gamla File
klassen verkligen saknade är en copy()
metod! Vi pratade om det i början av den här lektionen. Nu är det dags att träffa den!
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")));
}
}
Konsolutgång:
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
Nu vet du hur man kopierar filer programmatiskt! :) Naturligtvis Files
låter klassen dig inte bara hantera en fil själv, utan också arbeta med dess innehåll. Den har write()
metoden för att skriva data till en fil, och alla tre metoder för att läsa data: , , read()
och readAllBytes()
Vi readAllLines()
kommer att uppehålla oss i detalj vid den sista. Varför den där? Eftersom den har en väldigt intressant returtyp: List<String>
! Det vill säga, den ger oss en lista över alla rader i filen. Detta gör det naturligtvis väldigt bekvämt att arbeta med filinnehållet, eftersom hela filen rad för rad kan till exempel visas på konsolen med en vanlig for
loop:
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);
}
}
}
Konsolutgång:
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 bekvämt! :) Denna förmåga dök upp i Java 7. Stream API dök upp i Java 8. Den lägger till några delar av funktionell programmering till Java. Inklusive rikare filhanteringsmöjligheter. Föreställ dig att vi har följande uppgift: hitta alla rader som börjar med ordet "Som", konvertera dem till VERSALER och visa dem på konsolen. Hur skulle en lösning med Files
klassen se ut i Java 7? Något som det här:
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);
}
}
}
Konsolutgång:
AS THOUGH A BRIEF AND FLEETING OMEN,
PURE PHANTOM IN ENCHANTING LIGHT.
Uppdraget fullbordat, men tycker du inte att vår kod för en så enkel uppgift visade sig vara lite... mångtydig? Med Java 8:s Stream API ser lösningen mycket 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 uppnådde samma resultat, men med mycket mindre kod! Dessutom kan ingen säga att vi har tappat "läsbarheten". Jag tror att du enkelt kan kommentera vad den här koden gör, även utan att vara bekant med Stream API. Kort sagt, en Stream är en sekvens av element, över vilka du kan utföra olika operationer. Vi får ett Stream-objekt från Files.lines()
metoden och applicerar sedan 3 funktioner på det:
-
Vi använder
filter()
metoden för att bara välja de rader från filen som börjar med "Som". -
Vi går igenom alla valda rader med
map()
metoden och konverterar var och en av dem till VERSALER. -
Vi använder
collect()
metoden för att samla alla mottagna rader till enList
.
AS THOUGH A BRIEF AND FLEETING OMEN,
PURE PHANTOM IN ENCHANTING LIGHT.
Låt oss nu återgå till vårt bröd och smör, det vill säga filer :) Den sista möjligheten som vi kommer att överväga idag är att gå genom ett filträd . I moderna operativsystem ser filstrukturen oftast ut som ett träd: den har en rot och det finns grenar som kan ha andra grenar etc. Roten och grenarna är kataloger. Till exempel kan katalogen " С:// " vara roten. Den innehåller två grenar: " C://Nedladdningar " och " C://Users ". Var och en av dessa grenar har två grenar: " C://Downloads/Pictures ", " C://Downloads/Video ", " C://Users/JohnSmith ", " C://Users/Pudge2005". Och dessa grenar har i sin tur andra grenar etc. och det är därför vi kallar det ett träd. På Linux är strukturen liknande, men katalogen / är roten. Föreställ dig nu att vi måste börja vid





Files.walkFileTree ()
. Här är vad vi behöver göra. Först behöver vi en FileVisitor
. FileVisitor
är ett speciellt gränssnitt, där metoderna för att korsa ett filträd beskrivs. Det är särskilt där vi kommer att lägga logiken för att läsa innehållet i en fil och kontrollera om den innehåller den text vi behöver. Så här FileVisitor
ser vårt 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 det här fallet ärver vår klass SimpleFileVisitor
. Det här är en klass som implementerar FileVisitor
, där vi bara behöver åsidosätta en metod: visitFile()
. Här definierar vi vad som behöver göras med varje fil i varje katalog. Om du behöver mer komplex logik för att korsa filstrukturen bör du skriva din egen implementering av FileVisitor
. Du skulle behöva implementera ytterligare 3 metoder i den klassen:
-
preVisitDirectory()
: logiken att köra innan man går in i en mapp; -
visitFileFailed()
: logiken att köra om en fil inte kan besökas (ingen åtkomst eller av andra skäl); -
postVisitDirectory()
: logiken att köra efter att du har angett en mapp.
SimpleFileVisitor
. Logiken i visitFile()
metoden är ganska enkel: läs alla rader i filen, kontrollera om de innehåller det innehåll vi behöver, och i så fall skriv ut den absoluta sökvägen på konsolen. Den enda raden som kan orsaka dig svårigheter är denna:
return FileVisitResult.CONTINUE;
Egentligen är detta väldigt enkelt. Här beskriver vi helt enkelt vad programmet ska göra efter att filen har besökts och alla nödvändiga operationer har utförts. I vårt fall vill vi fortsätta att korsa trädet, så vi väljer alternativet CONTINUE
. Men alternativt kan vi ha ett annat mål: istället för att hitta alla filer som innehåller "Detta är filen vi behöver", hitta bara en sådan fil . Därefter bör programmet avslutas. I det här fallet skulle vår kod se exakt likadan ut, men istället för break skulle det finnas:
return FileVisitResult.TERMINATE;
Nåväl, låt oss köra vår kod och se om den fungerar.
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());
}
}
Konsolutgång:
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
Excellent! Det fungerade! :) Du kan också anta den här lilla utmaningen: ersätt SimpleFileVisitor
med en vanlig FileVisitor
, åsidosätt alla fyra metoderna och kom på ditt eget syfte med programmet. Du kan till exempel skriva ett program som loggar alla dess åtgärder: visa namnet på filen eller mappen före eller efter att du anger dem. Det var allt tills vidare. Ses snart! :)
GO TO FULL VERSION