пътеки
Paths е много прост клас с един статичен метод: get() . Създаден е единствено за получаване на обект Path от предадения низ or URI. Няма друга функционалност. Ето пример за това на работа:
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 . Нека да разберем Howво е Path и защо е необходимо :)
Пътека
Path като цяло е преработен аналог на класа File . С него се работи много по-лесно от File . Първо , много полезни (статични) методи бяха извадени и преместени в класа Files . Второ , беше наложен ред върху върнатите стойности на методите на интерфейса Path . В класа File методите върнаха or String , or boolean , or File . Не беше лесно да го разбера. Например, имаше метод getParent() , който върна низ, представляващ родителския път на текущия файл. Но имаше и аметод getParentFile() , който върна същото нещо, но под формата на File обект! Това явно е излишно. Съответно винтерфейса Path методът getParent() и други методи за работа с файлове просто връщат обект Path . Няма купчина опции - всичко е лесно и просто. Кои са някои от полезните методи, които има Path ? Ето някои от тях и примери How работят:-
getFileName() : връща името на file от пътя;
-
getParent() : връща "родителската" директория на текущия път (с други думи, директорията, разположена непосредствено по-горе в дървото на директорията);
-
getRoot() : връща "root" директорията, т.е. директорията в горната част на дървото на директориите;
-
startsWith() , endsWith() : проверка дали пътят започва/завършва с предадения път:
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); } }
Конзолен изход:
testFile.txt C:\Users\Username\Desktop C:\ true false
Обърнете внимание How работи методът endsWith() . Той проверява дали текущият път завършва с преминатия път . По-конкретно, дали е в пътя , а не в подаден низ .
Сравнете резултатите от тези две обаждания:
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")); } }
Конзолен изход:
false true
На метода endsWith() трябва да бъде подаден истински път, а не просто набор от знаци: в противен случай резултатът винаги ще бъде false, дори ако текущият път наистина завършва с тази последователност от знаци (Howто е случаят с "estFile.txt “ в примера по-горе).
Освен това Path има група методи, които опростяват работата с абсолютни (пълни) и относителни пътища .
-
boolean isAbsolute() връща true, ако текущият път е абсолютен:
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()); } }
Конзолен изход:
true
-
Path normalize() : "нормализира" текущия път, като премахва ненужните елементи от него. Може би знаете, че в популярните операционни системи символите "." (текуща директория) и ".." (родителска директория) често се използват за обозначаване на пътища. Например " ./Pictures/dog.jpg " означава, че текущата директория има папка "Pictures", която от своя страна съдържа файл "dog.jpg".
Вижте тук. Ако път, използващ "." or ".." се появява във вашата програма, методът normalize() ще ги премахне и ще създаде път, който не ги съдържа:
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()); } }
Конзолен изход:
C:\Users\Java\examples C:\Users\examples
-
Path relativize() : изчислява относителния път между текущия и преминалия път.
Например:
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)); } }
Конзолен изход:
Username\Desktop\testFile.txt
файлове
Files е помощен клас, който съдържа статичните методи, взети от класа File . Файловете са сравними с масиви or колекции . Разликата е, че работи с файлове, а не с масиви or колекции :) Фокусира се върху управлението на файлове и директории. Използвайки статичните методи на класа Files , можем да създаваме, изтриваме и преместваме файлове и директории. Тези операции се извършват с помощта наметодите createFile() (за директории createDirectory() ), move() и delete() . Ето How да ги използвате:
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")));
}
}
Тук първо създаваме файл ( метод Files.createFile() ) на работния плот. След това създаваме папка на същото място ( метод Files.createDirectory() ). След това преместваме file ( метод Files.move() ) от работния плот в тази нова папка и накрая изтриваме file ( метод Files.delete() ). Конзолен изход:
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
Забележка:подобно на методите на Path
интерфейса, много методи на Files
класа връщатPath
обект. Повечето от методите на Files
класа също приемат Path
обекти като вход. Тук Paths.get()
методът ще бъде ваш верен помощник - използвайте го добре. Какво друго е интересно в Files
? File
Това, което наистина липсваше на стария клас, е copy()
метод! Говорихме за това в началото на този урок. Сега е време да го срещнем!
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")));
}
}
Конзолен изход:
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
Вече знаете How да копирате файлове програмно! :) Разбира се, Files
класът ви позволява не само да управлявате самия файл, но и да работите с неговото съдържание. Има write()
метода за запис на данни във файл и всички 3 метода за четене на данни: read()
, readAllBytes()
, и readAllLines()
Ще се спрем подробно на последния. Защо този? Тъй като има много интересен тип връщане: List<String>
! Тоест, връща ни списък с всички редове във file. Разбира се, това прави много удобна работата със съдържанието на file, тъй като целият файл, ред по ред, може например да бъде показан на конзолата с помощта на обикновен цикъл 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);
}
}
}
Конзолен изход:
I still recall the wondrous moment:
When you appeared before my sight,
As though a brief and fleeting omen,
Pure phantom in enchanting light.
Супер удобно! :) Тази възможност се появи в Java 7. Stream API се появи в Java 8. Той добавя някои елементи на функционално програмиране към Java. Включително по-богати възможности за работа с файлове. Представете си, че имаме следната задача: да намерим всички редове, които започват с думата "As", да ги преобразуваме в ГЛАВНИ БУКВИ и да ги покажем на конзолата. Как би изглеждало решение, използващо Files
класа в Java 7? Нещо като това:
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);
}
}
}
Конзолен изход:
AS THOUGH A BRIEF AND FLEETING OMEN,
PURE PHANTOM IN ENCHANTING LIGHT.
Мисията е изпълнена, но не мислите ли, че за толкова проста задача нашият code се оказа малко... многословен? Използвайки Stream API на Java 8, решението изглежда много по-елегантно:
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);
}
}
Постигнахме същия резултат, но с много по-малко code! Още повече, че никой не може да каже, че сме загубor "четимост". Мисля, че можете лесно да коментирате Howво прави този code, дори без да сте запознати с API на потока. Накратко, потокът е последователност от елементи, над които можете да извършвате различни операции. Получаваме Stream обект от Files.lines()
метода и след това прилагаме 3 функции към него:
-
Използваме
filter()
метода, за да изберем само тези редове от file, които започват с "As". -
Преминаваме през всички избрани редове с помощта на
map()
метода и преобразуваме всеки от тях в ГЛАВНИ БУКВИ. -
Използваме
collect()
метода, за да съберем всички получени редове вList
.
AS THOUGH A BRIEF AND FLEETING OMEN,
PURE PHANTOM IN ENCHANTING LIGHT.
Сега да се върнем към нашия хляб и масло, тоест файловете :) Последната възможност, която ще разгледаме днес, е преминаването през файлово дърво . В съвременните операционни системи файловата структура най-често изглежда като дърво: има корен и има клонове, които могат да имат други клонове и т.н. Коренът и клоновете са директории. Например директорията " С:// " може да бъде основната. Той включва два клона: " C://Downloads " и " C://Users ". Всеки от тези клонове има два клона: " C://Downloads/Pictures ", " C://Downloads/Video ", " C://Users/JohnSmith ", " C://Users/Pudge2005". И тези клонове на свой ред имат други клонове и т.н. и затова го наричаме дърво. В Linux структурата е подобна, но директорията / е





Files.walkFileTree ()
. Ето Howво трябва да направим. Първо, имаме нужда от FileVisitor
. FileVisitor
е специален интерфейс, в който са описани методите за обхождане на файлово дърво. По-конкретно, там ще поставим логиката за четене на съдържанието на файл и проверка дали съдържа необходимия ни текст. Ето How 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("We found a file we need!");
System.out.println(file.toAbsolutePath());
break;
}
}
return FileVisitResult.CONTINUE;
}
}
В този случай нашият клас наследява SimpleFileVisitor
. Това е клас, който имплементира FileVisitor
, в който трябва да заменим само един метод: visitFile()
. Тук ние определяме Howво трябва да се направи с всеки файл във всяка директория. Ако имате нужда от по-сложна логика за преминаване през файловата структура, трябва да напишете своя собствена реализация на FileVisitor
. Ще трябва да внедрите още 3 метода в този клас:
-
preVisitDirectory()
: логиката за изпълнение преди влизане в папка; -
visitFileFailed()
: логиката за изпълнение, ако даден файл не може да бъде посетен (без достъп or по други причини); -
postVisitDirectory()
: логиката за изпълнение след влизане в папка.
SimpleFileVisitor
. Логиката вътре в visitFile()
метода е доста проста: прочетете всички редове във file, проверете дали съдържат необходимото съдържание и ако е така, отпечатайте абсолютния път на конзолата. Единственият ред, който може да ви затрудни е този:
return FileVisitResult.CONTINUE;
Всъщност това е много просто. Тук ние просто описваме Howво трябва да направи програмата, след като файлът бъде посетен и всички необходими операции са извършени. В нашия случай искаме да продължим да обикаляме дървото, така че избираме опцията CONTINUE
. Но, алтернативно, може да имаме различна цел: instead of да намираме всички файлове, които съдържат „Това е файлът, от който се нуждаем“, намерете само един такъв файл . След това програмата трябва да приключи. В този случай нашият code ще изглежда точно по същия начин, но instead of break ще има:
return FileVisitResult.TERMINATE;
Е, нека стартираме нашия code и да видим дали работи.
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());
}
}
Конзолен изход:
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
Отлично! Проработи! :) Можете също така да приемете това малко предизвикателство: заменете SimpleFileVisitor
с обикновен FileVisitor
, заменете всичките 4 метода и измислете своя собствена цел за програмата. Например, можете да напишете програма, която регистрира всичките си действия: показва името на file or папката преди or след въвеждането им. Това е всичко за сега. Ще се видим скоро! :)
GO TO FULL VERSION