File это старый способ доступа к файловой системе path это новый рекомендуемый способ
Данная статья является вольным переводом с авторскими комментариями учебного пособия компании Oracle, по работе с системой ввода-вывода, файлами, папками, реализованной в пакете java.nio.file. Сами разработчики предупреждают, что информация находится в процессе разработки и коррекции ошибок(в ожидании релиза JDK7), и предоставляется нам как ознакомительная, что, в прочем, не мешает нам использовать ее уже сейчас. Чтобы вывести изложение из чисто теоретического ключа, к более практическому, я сфокусирую внимание на тех «вкусностях», что помогут желающим написать, н-р, свой файловый менеджер. Итак, опустив вводную про то, что такое имя файла, структура файловой системы и прочее, приступим.
Класс Path
Прежде чем перейти к более интересному материалу, необходимо рассмотреть базовый класс Path.
Класс Path включает в себя различные методы, которые могут быть использованы для получения информации о пути, получения доступа к элементам пути, преобразования пути в другие формы, извлечения части пути. Существуют также методы для сравнения строк пути и методы для удаления избыточности.
Для создания экземпляра класса Path, воспульзуемся статическим методом get класса Paths, позволяющего создать путь из строки или URI.
Path path1 = Paths. get ( "/home/iam/folder" ) ;
Path path2 = Paths. get ( "C: \\ this \\ my \\ folder" ) ;
Path path3 = Paths. get ( "file:///Users/user/myfile.txt" ) ;
После того как экземпляр Path создан, мы можем получить некоторую информацию о пути:
//Path path = Paths.get("C:\\home\\joe\\foo"); // Microsoft Windows syntax
Path path = Paths. get ( "/home/iam/folder" ) ; // Solaris syntax
System . out . format ( "toString: %s%n" , path. toString ( ) ) ; //-->/home/iam/folder
System . out . format ( "getName: %s%n" , path. getName ( ) ) ; //-->folder
System . out . format ( "getName(0): %s%n" , path. getName ( 0 ) ) ; //-->home
System . out . format ( "getNameCount: %d%n" , path. getNameCount ( ) ) ; //-->3
System . out . format ( "subpath(0,2): %d%n" , path. subpath ( 0 , 2 ) ) ;
System . out . format ( "getParent: %s%n" , path. getParent ( ) ) ; //-->/home/iam/
System . out . format ( "getRoot: %s%n" , path. getRoot ( ) ) ; //-->/
System . out . format ( "isHidden: %s%n" , path. isHidden ( ) ) ; //-->false
метод subpath остался без вывода не случайно. Он упорно не хочет работать ни в Win7 ни Ubuntu, о чем я сообщил куда надо. Хотя этот пример взят с оригинального туторала, а в прочем это не единственная ошибочка.
Файлы и атрибуты файлов. Управление метаданными.
- BasicFileAttributeView – базовые атрибуты, поддерживаемые всеми реализациями файловых систем.
- DosFileAttributeView – расширяет базовые атрибуты, добавлением стандартных четырех бит, которые используются системами, поддерживающими атрибуты DOS.
- PosixFileAttributeView – поддержка атрибутов стандарта POSIX. Атрибуты включают в себя владельца файла( file owner), группу(group owner), и уровни прав доступа(access permissions).
- FileOwnerAttributeView – поддерживается всеми системами, реализующими концепцию владельца файла.
- AclFileAttributeView – поддерживает чтение и модификацию списков управления доступом файла( Access Control Lists (ACL)). Поддерживается модель NFSv4 ACL. Любая модель ACL, такая как Windows ACL, имеющая проработанную систему отображения к модели NFSv4, также должна поддерживаться.
- UserDefinedFileAttributeView – реализация поддержки пользовательских метаданных.
import java.io.IOException ;
import java.nio.file.Path ;
import java.nio.file.Paths ;
import java.nio.file.attribute.* ;
public class Main <
/**
* @param args the command line arguments
*/
public static void main ( String [ ] args ) throws IOException <
// TODO code application logic here
Path file = Paths. get ( "/home/aum/Downloads/demotivatory_15.jpg" ) ;
BasicFileAttributes attr = Attributes . readBasicFileAttributes ( file ) ;
if ( attr. creationTime ( ) != null ) <
System . out . println ( "creationTime: " + attr. creationTime ( ) ) ;
>
if ( attr. lastAccessTime ( ) != null ) <
System . out . println ( "lastAccessTime: " + attr. lastAccessTime ( ) ) ;
>
if ( attr. lastModifiedTime ( ) != null ) <
System . out . println ( "lastModifiedTime: " + attr. lastModifiedTime ( ) ) ;
>
System . out . println ( "isDirectory: " + attr. isDirectory ( ) ) ;
System . out . println ( "isOther: " + attr. isOther ( ) ) ;
System . out . println ( "isRegularFile: " + attr. isRegularFile ( ) ) ;
System . out . println ( "isSymbolicLink: " + attr. isSymbolicLink ( ) ) ;
System . out . println ( "size: " + attr. size ( ) ) ;
>
>
Результат:
run:
lastAccessTime: 2011-02-14T14:16:32Z
lastModifiedTime: 2011-02-04T02:17:27Z
isDirectory: false
isOther: false
isRegularFile: true
isSymbolicLink: false
size: 64613
BUILD SUCCESSFUL (total time: 0 seconds)
На этом вводную предлагаю считать завершенной. За бортом осталось множество методов «синтаксической» работы с Path: удаление избыточности в пути, преобразование к абсолютному пути, сравнение путей, создание путей из объеденения и т.п. Всю необходимую информацию вы можете найти здесь (класс Path) И теперь мы смело можем перейти к более сложному, но и более интересному материалу.
Обход дерева файлов
Получение информации о папках и файлах на диске, довольно типичная задача для прикладных программ. Пакет java.nio.file предлагает нам удобное решение такой задачи, предоставляя интерфейс FileVisitor.
FileVisitor определяет требуемое поведение в ключевых точках прохождения процесса: когда файл посещен, прежде чем получить доступ к каталогу, после получения доступа к каталогу, или в случае отказа. Интерфейс состоит из пяти(! оставлю слово пять из оригинального текста, хотя как не старался нашел только 4! метода ) методов, которые соответствуют этим ситуациях:
- preVisitDirectory – вызывается до входа в папку
- postVisitDirectory – вызывается после «просмотра» всех объектов каталога. В случае возникновения ошибки, вызывается исключение и передается методу
- visitFile – вызывается для получения информации о файле, обрабатываемом в данный момент. В метод передаются атрибуты файла BasicFileAttributes, или мы можем передать определенный набор атрибутов, н-р можем выбрать чтение атрибутов DosFileAttributeView, чтобы определить является ли файл скрытым(«hidden»).
- visitFileFailed – вызывается при невозможности получить доступ к файлу. В этом случае вызывается исключение и передается методу. Обработка этого события может быть различной(вызов исключения, запись в лог или вывод информации на консоль и т.д.
import java.nio.file.FileVisitOption ;
import java.util.EnumSet ;
import java.nio.file.Files ;
import java.nio.file.Paths ;
import java.io.IOException ;
import java.nio.file.FileVisitResult ;
import java.nio.file.Path ;
import java.nio.file.SimpleFileVisitor ;
import java.nio.file.attribute.BasicFileAttributes ;
import static java. nio . file . FileVisitResult . *;
//Используем класс SimpleFileVisitor, который реализовывает методы интерфейса FileVisitor
public class PrintFiles extends SimpleFileVisitor < Path ><
//Выводим информацию о обрабатываемом в данный момент файле.
// метод Files.probeContentType выводит информацию о типе контента
@Override
public FileVisitResult visitFile ( Path file, BasicFileAttributes attr ) throws IOException <
if ( attr. isSymbolicLink ( ) ) <
System . out . format ( "Symbolic link: %s " , file ) ;
> else if ( attr. isRegularFile ( ) ) <
System . out . format ( "Regular file: %s Content is %s%n " , file,Files. probeContentType ( file ) ) ;
> else <
System . out . format ( "Other: %s " , file ) ;
>
System . out . println ( "(" + attr. size ( ) + "bytes)" ) ;
return CONTINUE ;
>
//Выводим информацию о посещенном каталоге
@Override
/* Перечисление FileVisitResult имеет следующие варианты
CONTINUE продолжить проход.
SKIP_SIBLINGS продолжить проход без осмотра дочерних папок.
SKIP_SUBTREE продолжить без просмотра объектов данной папки.
TERMINATE заверщить.
*/
public FileVisitResult postVisitDirectory ( Path dir, IOException exc ) <
System . out . format ( "Directory: %s%n" , dir ) ;
return CONTINUE ;
>
//в случае ошибки доступа к файлу выбрасывается исключение IOException
@Override
public FileVisitResult visitFileFailed ( Path file, IOException exc ) <
System . err . println ( exc ) ;
return CONTINUE ;
>
public static void main ( String [ ] args ) throws IOException <
//создаем объект Path
Path startingDir = Paths. get ( "/home/aum/myjobs/" ) ;
//создаем экземпляр нашего класса, реализующего FileVisit
PrintFiles pf = new PrintFiles ( ) ;
//создаем экземпляр EnumSet, необходимый нам как параметр, и указывающий,
// что программа при прохождении дерева файлов, следует по ссылкам
EnumSet < FileVisitOption >options = EnumSet. of ( FileVisitOption. FOLLOW_LINKS ) ;
int maxDepth = 2 ; //максимальное число уровней каталога для просмотра
/* Запуск анализа дерева файлов. Используется один из методов класса Files*/
Files. walkFileTree ( startingDir, options, maxDepth, pf ) ;
>
>
Результат
run:
Regular file: /home/aum/myjobs/sys.txt Content is text/plain
(11362bytes)
Regular file: /home/aum/myjobs/vzriv.mp3 Content is audio/mpeg
(2336827bytes)
Regular file: /home/aum/myjobs/report.html Content is text/html
(24574bytes)
Regular file: /home/aum/myjobs/examples.desktop Content is application/x-desktop
(179bytes)
Directory: /home/aum/myjobs/java
Directory: /home/aum/myjobs
BUILD SUCCESSFUL (total time: 0 seconds)
И в завершении о производительности. Н-р, код указаный выше, выполняется (на моем каталоге /home) так:
Objects found 19931 Total Size 2329851621 byte
BUILD SUCCESSFUL (total time: 38 seconds)
системные характеристики
Ubuntu 10.4
Kernel Linux 2.6.32-28
Gnom 2.30.2
Memory 1.9 G
Intel® Core(TM) i3 CPU M330 @ 2.13 GHz
Работа с директориями в Node.js
Модуль fs предоставляет в распоряжение разработчика много удобных методов, которые можно использовать для работы с директориями.
Работа с файловыми дескрипторами в Node.js
Прежде чем вы сможете взаимодействовать с файлами, находящимися в файловой системе вашего сервера, вам необходимо получить дескриптор файла.
Дескриптор можно получить, воспользовавшись для открытия файла асинхронным методом open() из модуля fs :
Обратите внимание на второй параметр, r , использованный при вызове метода fs.open() . Это — флаг, который сообщает системе о том, что файл открывают для чтения. Вот ещё некоторые флаги, которые часто используются при работе с этим и некоторыми другими методами:
- r+ — открыть файл для чтения и для записи.
- w+ — открыть файл для чтения и для записи, установив указатель потока в начало файла. Если файл не существует — он создаётся.
- a — открыть файл для записи, установив указатель потока в конец файла. Если файл не существует — он создаётся.
- a+ — открыть файл для чтения и записи, установив указатель потока в конец файла. Если файл не существует — он создаётся.
После получения дескриптора любым из вышеописанных способов вы можете производить с ним необходимые операции.
▍Получение информации о пути к файлу
Если у вас есть путь к файлу, то, используя возможности модуля path , вы можете, в удобном для восприятия и дальнейшей обработки виде, узнать подробности об этом пути. Выглядит это так:
Здесь, в строке notes , хранится путь к файлу. Для разбора пути использованы следующие методы модуля path :
- dirname() — возвращает родительскую директорию файла.
- basename() — возвращает имя файла.
- extname() — возвращает расширение файла.
▍Удаление папки
Для того чтобы удалить папку, можно воспользоваться методами fs.rmdir() или fs.rmdirSync() . Надо отметить, что удаление папки, в которой что-то есть, задача несколько более сложная, чем удаление пустой папки. Если вам нужно удалять такие папки, воспользуйтесь пакетом fs-extra, который весьма популярен и хорошо поддерживается. Он представляет собой замену модуля fs , расширяющую его возможности.
Метод remove() из пакета fs-extra умеет удалять папки, в которых уже что-то есть.
Установить этот модуль можно так:
Вот пример его использования:
Его методами можно пользоваться в виде промисов:
Допустимо и применение конструкции async/await:
Данные о файлах
С каждым файлом связан набор данных о нём, исследовать эти данные можно средствами Node.js. В частности, сделать это можно, используя метод stat() из модуля fs .
Вызывают этот метод, передавая ему путь к файлу, и, после того, как Node.js получит необходимые сведения о файле, он вызовет коллбэк, переданный методу stat() . Вот как это выглядит:
В Node.js имеется возможность синхронного получения сведений о файлах. При таком подходе главный поток блокируется до получения свойств файла:
Информация о файле попадёт в константу stats . Что это за информация? На самом деле, соответствующий объект предоставляет нам большое количество полезных свойств и методов:
- Методы .isFile() и .isDirectory() позволяют, соответственно, узнать, является ли исследуемый файл обычным файлом или директорией.
- Метод .isSymbolicLink() позволяет узнать, является ли файл символической ссылкой.
- Размер файла можно узнать, воспользовавшись свойством .size .
▍Чтение содержимого папки
Для того чтобы прочесть содержимое папки, можно воспользоваться методами fs.readdir() и fs.readdirSync() . В этом примере осуществляется чтение содержимого папки — то есть — сведений о том, какие файлы и поддиректории в ней имеются, и возврат их относительных путей:
Вот так можно получить полный путь к файлу:
Результаты можно отфильтровать для того, чтобы получить только файлы и исключить из вывода директории:
Пути к файлам в Node.js и модуль path
Путь к файлу — это адрес того места в файловой системе, где он расположен.
В Linux и macOS путь может выглядеть так:
В Windows пути выглядят немного иначе:
На различия в форматах записи путей при использовании разных операционных систем следует обращать внимание, учитывая операционную систему, используемую для развёртывания Node.js-сервера.
В Node.js есть стандартный модуль path , предназначенный для работы с путями к файлам. Перед использованием этого модуля в программе его надо подключить:
Присоединение данных к файлу
Метод fs.appendFile() (и его синхронную версию — fs.appendFileSync() ) удобно использовать для присоединения данных к концу файла:
▍path.basename()
Возвращает последний фрагмент пути. Передав второй параметр этому методу можно убрать расширение файла.
Запись файлов в Node.js
В Node.js легче всего записывать файлы с использованием метода fs.writeFile() :
Есть и синхронная версия того же метода — fs.writeFileSync() :
Эти методы, по умолчанию, заменяют содержимое существующих файлов. Изменить их стандартное поведение можно, воспользовавшись соответствующим флагом:
Тут могут использоваться флаги, которые мы уже перечисляли в разделе, посвящённом дескрипторам. Подробности о флагах можно узнать здесь.
Об использовании потоков
Выше мы описывали методы, которые, выполняя запись в файл, пишут в него весь объём переданных им данных, после чего, если используются их синхронные версии, возвращают управление программе, а если применяются асинхронные версии — вызывают коллбэки. Если вас такое состояние дел не устраивает — лучше будет воспользоваться потоками.
▍path.parse()
Преобразует путь в объект, свойства которого представляют отдельные части пути:
- root : корневая директория.
- dir : путь к файлу, начиная от корневой директории
- base : имя файла и расширение.
- name : имя файла.
- ext : расширение файла.
В результате его работы получается такой объект:
▍path.dirname()
Возвращает ту часть пути, которая представляет имя директории:
Чтение файлов в Node.js
Самый простой способ чтения файлов в Node.js заключается в использовании метода fs.readFile() с передачей ему пути к файлу и коллбэка, который будет вызван с передачей ему данных файла (или объекта ошибки):
Если надо, можно воспользоваться синхронной версией этого метода — fs.readFileSync() :
По умолчанию при чтении файлов используется кодировка utf8 , но кодировку можно задать и самостоятельно, передав методу соответствующий параметр.
Методы fs.readFile() и fs.readFileSync() считывают в память всё содержимое файла. Это означает, что работа с большими файлами с применением этих методов серьёзно отразится на потреблении памяти вашим приложением и окажет влияние на его производительность. Если с такими файлами нужно работать, лучше всего воспользоваться потоками.
3. Разделение пути на части
Метод getParent() возвращает путь, который указывает на родительскую директорию для текущего пути. Независимо от того, был этот путь директорией или файлом:
Метод getFileName() возвращает одно имя файла (или директории) — то, что идет после последнего разделителя:
— Отлично. Только что Билаабо рассказывал кучу интересного про File, и как с ним работать.
— Думаю, у меня как раз есть что добавить по этой теме.
— Да? Тогда с удовольствием послушаю.
— Тогда слушай. Java постоянно развивается, постоянно ищутся новые способы делать различные вещи эффективнее. Еще в Java 7 была добавлена альтернатива классу File.
— Ага. Взяли за основу класс File, добавили в него немного нового, переименовывали методы, а в конце еще и разделили на два. Так что теперь есть два новых класса – Path и Files . Path – это, фактически новый аналог класса File, а Files – это утилитный класс (по аналогии с классами Arrays & Collections), в него вынести все статические методы класса File. Так «правильнее» с точки зрения ООП.
— Ну, раз с точки зрения ООП, то – ок. А что поменялось-то?
— Во-первых, отказались от дублирования методов, которые возвращали String и File. В классе Path все методы возвращают Path .
Во-вторых, убрали многие статические утилитные методы в класс Files .
В третьих, удобнее стало работать с относительными путями.
Вот список методов:
Методы класса Path | Описание |
---|---|
boolean isAbsolute() | Возвращает true, если путь – абсолютный. |
Path getRoot() | Возвращает корень текущего пути – директорию самого верхнего уровня. |
Path getFileName() | Возвращает имя файла из текущего пути. |
Path getParent() | Возвращает директорию из текущего пути. |
boolean startsWith(Path other) | Проверяет, что текущий путь начинается с переданного пути. |
boolean endsWith(Path other) | Проверяет, что текущий путь заканчивается на переданный путь. |
Path normalize() | Нормализует текущий путь. Например, приводит путь «c:/dir/dir2/../a.txt» к пути «c:/dir/a.txt» |
Path relativize(Path other) | Вычисляет относительный путь двух путей – «разницу путей» |
Path resolve(String other) | Восстанавливает абсолютный путь по текущему и относительному. |
URI toUri() | Возвращает URI текущего пути/файла. |
Path toAbsolutePath() | Приводит путь к абсолютному, если был относительный. |
File toFile() | Возвращает объект File, который соответствует текущему объекту Path. |
— А текущий путь – это что?
— Это тот путь, который был передан в конструктор объекта Path, методы которого вызываются. Path – это «путь» по-английски.
— Ок. А какие методы есть у класса Files ?
— Ну и куда же ты так спешишь-то? Сейчас все расскажу. Вот основные методы:
Методы класса Files | Описание |
---|---|
Path createFile(…) | Создает файл на диске. |
Path createDirectory(…) | Создает директорию. |
Path createDirectories(…) | Создает директорию и поддиректории. |
Path createTempFile(…) | Создает «временный файл» |
Path createTempDirectory(…) | Создает «временную директорию» |
void delete(Path path) | Удаляет файл/директорию. |
Path copy(Path source, Path target,…) | Копирует файл. |
Path move(Path source, Path target,…) | Перемещает файл. |
boolean isSameFile(Path, Path) | Сравнивает два файла. |
boolean isDirectory(Path) | Путь — это директория? |
boolean isRegularFile(Path) | Путь – это файл? |
long size(Path) | Возвращает размер файла. |
boolean exists(Path) | Объект с таким именем существует? |
boolean notExists(Path) | Объект с таким именем не существует? |
long copy(InputStream, OutputStream) | Копирует байты из InputStream в OutputStream. |
long copy(Path, OutputStream) | Копирует все байты из Path в OutputStream. |
long copy(InputStream, Path) | Копирует все байты из InputStream в Path. |
byte[] read(InputStream, int initialSize) | Читает массив байт из InputStream. |
byte[] readAllBytes(Path path) | Читает все байты из InputStream. |
List readAllLines(Path path. ) | Читает текстовый файл, возвращает список строк. |
Path write(Path path, byte[] bytes,…) | Пишет массив байт в файл. |
— Как интересно, столько крутых функций, и все в одном месте.
А зачем нужны временные файлы?
— А сложно скачать файл из интернета?
— Очень просто. Смотри пример:
— Да, а что ты ожидал тут увидеть? Тут всего 4 строчки.
Строка номер 1. Создается объект URL, куда передается ссылка в интернете на файл с картинкой.
Строка номер 2. У объекта url открываться поток на чтение файла – InputStream.
Строка номер 4. С помощью метода createTempFile создается временный файл.
Строка номер 5. Метод Files.copy копирует данные из inputStream в tempFile . Все.
— Отлично, рад, что тебе понравилось. Думаю, с остальными методами ты разберёшься сам. А я попрошу Диего дать тебе несколько задачек на них.
Сегодня, в девятой части перевода руководства по Node.js, мы поговорим о работе с файлами. В частности, речь пойдёт о модулях fs и path — о файловых дескрипторах, о путях к файлам, о получении информации о файлах, об их чтении и записи, о работе с директориями.
▍Проверка существования папки
Для того чтобы проверить, существует ли директория и может ли Node.js получить к ней доступ, учитывая разрешения, можно использовать метод fs.access() .
▍Создание новой папки
Для того чтобы создавать новые папки, можно воспользоваться методами fs.mkdir() и fs.mkdirSync() :
▍path.extname()
Возвращает ту часть пути, которая представляет расширение файла:
▍path.resolve()
Находит абсолютный путь на основе переданного ему относительного пути:
2. Методы типа Path
У интерфейса Path есть довольно много интересных методов. Самые интересные представлены в таблице ниже.
Метод | Описание |
---|---|
Возвращает родительскую директорию | |
Возвращает имя файла без директории | |
Возвращает корневую директорию из пути | |
Проверяет, что текущий путь — абсолютный | |
Преобразует путь в абсолютный | |
Убирает шаблоны в имени директории. | |
Строит новый абсолютный путь из абсолютного и относительного. | |
Получает относительный путь из двух абсолютных путей. | |
Проверяет, что текущий путь начинается с пути | |
Проверяет, что текущий путь заканчивается на путь | |
Дробит путь на части с помощью разделителя / . Возвращает количество частей. | |
Дробит путь на части с помощью разделителя / . Возвращает часть по ее номеру. | |
Дробит путь на части с помощью разделителя / . Возвращает часть пути, заданную интервалом. | |
Преобразует объект Path в устаревший объект File | |
Преобразует объект Path в объект типа URI |
Ниже идет краткое описание существующих методов.
▍path.relative()
Принимает, в качестве аргументов, 2 пути. Возвращает относительный путь из первого пути ко второму, основываясь на текущей рабочей директории:
Модуль fs
Выше мы уже сталкивались с некоторыми методами модуля fs , применяемыми при работе с файловой системой. На самом деле, он содержит ещё много полезного. Напомним, что он не нуждается в установке, для того, чтобы воспользоваться им в программе, его достаточно подключить:
После этого у вас будет доступ к его методам, среди которых отметим следующие, некоторые из которых вам уже знакомы:
- fs.rename()
- fs.renameSync()
- fs.write()
- fs.writeSync()
В Node.js 10 имеется экспериментальная поддержка этих API, основанных на промисах.
Исследуем метод fs.rename() . Вот асинхронная версия этого метода, использующая коллбэки:
При использовании его синхронной версии для обработки ошибок используется конструкция try/catch :
Основное различие между этими вариантами использования данного метода заключается в том, что во втором случае выполнение скрипта будет заблокировано до завершения файловой операции.
▍path.normalize()
Пытается выяснить реальный путь на основе пути, который содержит символы, использующиеся при построении относительных путей вроде . , .. и // :
Модуль path
Модуль path, о некоторых возможностях которого мы тоже уже говорили, содержит множество полезных инструментов, позволяющих взаимодействовать с файловой системой. Как уже было сказано, устанавливать его не нужно, так как он является частью Node.js. Для того чтобы пользоваться им, его достаточно подключить:
Свойство path.sep этого модуля предоставляет символ, использующийся для разделения сегментов пути ( \ в Windows и / в Linux и macOS), а свойство path.delimiter даёт символ, используемый для отделения друг от друга нескольких путей ( ; в Windows и : в Linux и macOS).
Рассмотрим и проиллюстрируем примерами некоторые методы модуля path .
▍path.isAbsolute()
Возвращает истинное значение если путь является абсолютным:
Paths
Paths — это совсем простой класс с единственным статическим методом get() . Его создали исключительно для того, чтобы из переданной строки или URI получить объект типа Path . Другой функциональности у него нет. Вот пример его работы: Не самый сложный класс, да? :) Ну, раз уж мы получили объект типа Path , давай разбираться, что это за Path такой и зачем он нужен :)
getFileName() — возвращает имя файла из пути;
getParent() — возвращает «родительскую» директорию по отношению к текущему пути (то есть ту директорию, которая находится выше по дереву каталогов);
getRoot() — возвращает «корневую» директорию; то есть ту, которая находится на вершине дерева каталогов;
startsWith() , endsWith() — проверяют, начинается/заканчивается ли путь с переданного пути:
Вывод в консоль:
testFile.txt
C:\Users\Username\Desktop
C:\
true
false
Обрати внимание на то, как работает метод endsWith() . Он проверяет, заканчивается ли текущий путь на переданный путь. Именно на путь, а не на набор символов.
Сравни результаты этих двух вызовов:
Вывод в консоль:
false
true
В метод endsWith() нужно передавать именно полноценный путь, а не просто набор символов: в противном случае результатом всегда будет false, даже если текущий путь действительно заканчивается такой последовательностью символов (как в случае с “estFile.txt” в примере выше).
Кроме того, в Path есть группа методов, которая упрощает работу с абсолютными (полными) и относительными путями.
boolean isAbsolute() — возвращает true, если текущий путь является абсолютным:
Вывод в консоль:
Path normalize() — «нормализует» текущий путь, удаляя из него ненужные элементы. Ты, возможно, знаешь, что в популярных операционных системах при обозначении путей часто используются символы “.” (“текущая директория”) и “..” (родительская директория). Например: “./Pictures/dog.jpg” обозначает, что в той директории, в которой мы сейчас находимся, есть папка Pictures, а в ней — файл “dog.jpg”
Так вот. Если в твоей программе появился путь, использующий “.” или “..”, метод normalize() позволит удалить их и получить путь, в котором они не будут содержаться:
Вывод в консоль:
C:\Users\Java\examples
C:\Users\examples
Path relativize() — вычисляет относительный путь между текущим и переданным путем.
Вывод в консоль:
Username\Desktop\testFile.txt
▍Переименование папки
Для переименования папки можно воспользоваться методами fs.rename() и fs.renameSync() . Первый параметр — это текущий путь к папке, второй — новый:
Переименовать папку можно и с помощью синхронного метода fs.renameSync() :
▍Работа с путями к файлам
Несколько частей пути можно объединить, используя метод path.join() :
Найти абсолютный путь к файлу на основе относительного пути к нему можно с использованием метода path.resolve() :
В данном случае Node.js просто добавляет /flavio.txt к пути, ведущем к текущей рабочей директории. Если при вызове этого метода передать ещё один параметр, представляющий путь к папке, метод использует его в качестве базы для определения абсолютного пути:
Если путь, переданный в качестве первого параметра, начинается с косой черты — это означает, что он представляет собой абсолютный путь.
Вот ещё один полезный метод — path.normalize() . Он позволяет найти реальный путь к файлу, используя путь, в котором содержатся спецификаторы относительного пути вроде точки ( . ), двух точек ( .. ), или двух косых черт:
Методы resolve() и normalize() не проверяют существование директории. Они просто находят путь, основываясь на переданным им данным.
Итоги
▍path.join()
Соединяет несколько частей пути:
Files
С помощью метода filter() отбираем только те строки из файла, которые начинаются с «Как».
Проходимся по всем отобранным строкам с помощью метода map() и приводим каждую из них к UPPER CASE.
Объединяем все получившиеся строки в List с помощью метода collect() .
preVisitDirectory() — логика, которую надо выполнять перед входом в папку;
visitFileFailed() — что делать, если вход в файл невозможен (нет доступа, или другие причины);
postVisitDirectory() — логика, которую надо выполнять после захода в папку.
Если вы хотите написать программу, которая делает что-то с файлами на диске, это у вас очень легко получится. В Java очень много классов, которые помогают вам работать как с самими файлами, так и с их содержимым.
В ранних версиях Java для работы с файлами использовались классы типа File и FileInputStream . Но теперь класс File считается устаревшим, и использовать его не рекомендуется. Вы, конечно, можете еще встретить его в коде, параметрах методов или конструкторах классов.
Мы будем начинать изучение работы с файлами сразу с класса Path . Path — это класс, который пришел на смену File . Работа с ним безопаснее и эффективнее.
Класс Path
Технически Path — это не класс, а интерфейс. Так сделано для того, чтобы можно было под каждую операционную (и файловую) систему писать свой класс-наследник Path .
У Windows свои стандарты написания пути файлов, у Linux — свои. А ведь в мире еще много операционных систем, и у каждой — свои стандарты.
Поэтому везде в методах для работы с файлами указан интерфейс Path , а реально работа идет с его классами-наследниками: WindowsPath , UnixPath , .
Создание объекта Path
Чтобы создать объект Path (на самом деле это будет объект класса-наследника — WindowsPath ), нужно воспользоваться командой вида:
Где имя — это имя переменной типа Path . путь — это путь к файлу (или директории) вместе с именем файла (или директории). А of — статический метод класса Path .
Метод of() используется для того, чтобы создать объекты типа WindowsPath если программа запускается под Windows, а если программа запускается под Linux — объекты UnixPath . Вы не можете создать объект типа Path с помощью кода вида new Path() .
Код | Примечание |
---|---|
Путь к файлу | |
Путь к директории |
Файл (или директория) не обязаны существовать, чтобы мог существовать валидный объект типа Path . Может вы только хотите создать файл. Объект типа Path — это как продвинутая версия типа String — он не привязан к конкретному файлу на диске: он просто хранит некий путь на диске и все.
Читайте также: