1. Обзор
В Java Path
и File
— это классы, отвечающие за файловые операции ввода-вывода. Они выполняют одни и те же функции, но относятся к разным пакетам.
В этом уроке мы обсудим различия между этими двумя классами. Мы начнем с краткого обзора класса. Затем мы поговорим о некоторых устаревших недостатках. Наконец, мы узнаем, как перенести функции между обоими API.
2. Класс java.io.Файл
Начиная с самых первых версий, Java предоставляет собственный пакет java.io
, который содержит почти все классы, которые могут нам когда-либо понадобиться для выполнения операций ввода и вывода. Класс File
является абстрактным представлением путей к файлам и каталогам :
File file = new File("foreach/tutorial.txt");
Экземпляры класса File
неизменяемы — после создания абстрактный путь, представленный этим объектом, никогда не изменится.
3. Класс java.nio.file.Path
Класс Path
является частью обновления NIO2 , которое появилось в Java с версией 7. Он предоставляет совершенно новый API для работы с вводом -выводом . Более того, как и устаревший класс File ,
Path
также создает объект, который можно использовать для поиска файла в файловой системе . **
**
Точно так же он может выполнять все операции , которые можно выполнить с классом File :
Path path = Paths.get("foreach/tutorial.txt");
Вместо использования конструктора, как в случае с File
API, мы создаем экземпляр Path
, используя статический метод java.nio.file.Paths.get()
.
4. Недостатки файлового
класса
После этого краткого обзора двух классов давайте теперь обсудим оба API и ответим на вопрос: если они обеспечивают одинаковую функциональность, почему Oracle решила добавить новый API и какой из них мне следует использовать?
Как мы знаем, пакет java
.io
поставлялся с первым выпуском Java JDK, что позволяло нам выполнять операции ввода-вывода. С тех пор многие разработчики сообщали о многих недостатках, отсутствующих функциях и проблемах с некоторыми из его возможностей.
4.1. Обработка ошибок
Самая распространенная проблема — плохая обработка ошибок. Многие методы не сообщают нам никаких подробностей о возникшей проблеме и даже не выдают исключений.
Предположим, у нас есть простая программа, которая удаляет файл:
File file = new File("foreach/tutorial.txt");
boolean result = file.delete();
Этот код компилируется и успешно работает без каких-либо ошибок. Конечно, у нас есть флаг результата
, содержащий ложное
значение, но мы не знаем причину этого сбоя. Файл может не существовать, или у программы может не быть разрешения на его удаление.
Теперь мы можем переписать ту же функциональность, используя более новый API NIO2:
Path path = Paths.get("foreach/tutorial.txt");
Files.delete(path);
Теперь компилятор требует от нас обработки IOException
. Более того, у выброшенного исключения есть подробности о его сбое, которые сообщат вам, например, если файл не существует.
4.2. Поддержка метаданных
Класс File
в пакете java.io
плохо поддерживает метаданные, что приводит к проблемам на разных платформах с операциями ввода-вывода, требующими метаинформации о файлах.
Метаданные могут также включать разрешения, владельца файла и атрибуты безопасности. Из-за этого класс File
вообще не поддерживает символические ссылки , а метод rename()
работает неодинаково на разных платформах. ``
4.3. Масштабирование и производительность метода
Также существует проблема с производительностью, поскольку методы класса File
не масштабируются. Это приводит к проблемам с некоторыми каталогами с большим количеством файлов. Перечисление содержимого каталога может привести к зависанию, вызывая проблемы с ресурсами памяти . Наконец, это может привести к отказу в обслуживании.
Из-за некоторых из этих недостатков Oracle разработал улучшенный API NIO2. Разработчики должны начинать новые проекты, используя этот новый пакет java.nio
вместо устаревших классов, где это возможно.
5. Функциональность отображения
Чтобы исправить некоторые пробелы в пакете java.io
, Oracle подготовила собственную сводку недостатков , помогающую разработчикам мигрировать между API.
Пакет NIO2 `` предоставляет все устаревшие функции, включая улучшения для упомянутых недостатков. Из-за большого количества приложений, которые все еще могут использовать этот устаревший API, Oracle в настоящее время не планирует объявлять устаревшим или удалять старый API в будущих выпусках.
В новом API вместо методов экземпляра мы используем статические из класса java.nio.file.Files .
Давайте теперь быстро сравним эти API.
5.1. Экземпляры файлов
и путей
Основное отличие, конечно же, в названии пакета и класса:
java.io.File file = new java.io.File("foreach/tutorial.txt");
java.nio.file.Path path = java.nio.file.Paths.get("foreach/tutorial.txt");
Здесь мы создаем объект File с помощью конструктора, а
Path
получаем с помощью статического метода. Мы также можем разрешать сложные пути, используя несколько аргументов:
File file = new File("foreach", "tutorial.txt");
Path path = Paths.get("foreach", "tutorial.txt");
И мы можем добиться того же результата, объединив метод resolve()
:
Path path2 = Paths.get("foreach").resolve("tutorial.txt");
Более того, мы можем конвертировать объекты между API, используя методы toPath()
и toFile()
:
Path pathFromFile = file.toPath();
File fileFromPath = path.toFile();
5.2. Управление файлами и каталогами
Оба API предоставляют методы для управления файлами и каталогами. Мы продемонстрируем это, используя ранее созданные объекты-экземпляры.
Для создания файлов мы можем использовать методы createNewFile( )
и Files.createFile()
:
boolean result = file.createNewFile();
Path newPath = Files.createFile(path);
Чтобы создать каталог , нам нужно использовать mkdir()
или Files.createDirectory()
:
boolean result = file.mkdir();
File newPath = Files.createDirectory(path);
Существуют дополнительные варианты этих методов для включения всех несуществующих подкаталогов с помощью методов mkdirs()
и Files.createDirectories()
:
boolean result = file.mkdirs();
File newPath = Files.createDirectories(path);
Когда мы хотим переименовать или переместить файл , нам нужно создать другой экземпляр объекта и использовать renameTo()
или Files.move()
:
boolean result = file.renameTo(new File("foreach/tutorial2.txt"));
Path newPath = Files.move(path, Paths.get("foreach/tutorial2.txt"));
Чтобы выполнить операцию удаления , мы используем delete()
или Files.delete()
:
boolean result = file.delete();
Files.delete(Paths.get(path));
Обратите внимание, что устаревшие методы возвращают флаг с результатом, равным false
, в случае каких-либо ошибок. Методы NIO2 возвращают новый экземпляр Path
, за исключением операции удаления, которая генерирует исключение IOException
при возникновении ошибок.
5.3. Чтение метаданных
Мы также можем получить некоторую базовую информацию о файлах, такую как разрешения или типы. Как и раньше, нам нужен экземпляр объекта:
// java.io API
boolean fileExists = file.exists();
boolean fileIsFile = file.isFile();
boolean fileIsDir = file.isDirectory();
boolean fileReadable = file.canRead();
boolean fileWritable = file.canWrite();
boolean fileExecutable = file.canExecute();
boolean fileHidden = file.isHidden();
// java.nio API
boolean pathExists = Files.exists(path);
boolean pathIsFile = Files.isRegularFile(path);
boolean pathIsDir = Files.isDirectory(path);
boolean pathReadable = Files.isReadable(path);
boolean pathWritable = Files.isWritable(path);
boolean pathExecutable = Files.isExecutable(path);
boolean pathHidden = Files.isHidden(path);
5.4. Методы имени пути
В заключение давайте быстро рассмотрим методы в классе File
для получения пути к файловой системе . Имейте в виду, что, в отличие от предыдущих примеров, большинство из них выполняются непосредственно на экземплярах объектов.
Чтобы получить абсолютные или канонические пути , мы можем использовать:
// java.io API
String absolutePathStr = file.getAbsolutePath();
String canonicalPathStr = file.getCanonicalPath();
// java.nio API
Path absolutePath = path.toAbsolutePath();
Path canonicalPath = path.toRealPath().normalize();
Хотя объект Path
неизменяем, он возвращает новый экземпляр. Более того, в NIO2 API есть методы toRealPath()
и normalize()
, которые мы можем использовать для удаления избыточности.
Преобразование в URI
можно выполнить с помощью методов toUri()
:
URI fileUri = file.toURI();
URI pathUri = path.toUri();
Кроме того, мы можем перечислить содержимое каталога :
// java.io API
String[] list = file.list();
File[] files = file.listFiles();
// java.nio API
DirectoryStream<Path> paths = Files.newDirectoryStream(path);
NIO2 API возвращает собственный объект DirectoryStream
, реализующий интерфейс Iterable .
6. Заключение
Начиная с Java 7 разработчики теперь могут выбирать между двумя API для работы с файлами. В этой статье мы обсудили некоторые различные недостатки и проблемы, связанные с классом java.io.File .
Чтобы исправить их, Oracle решила доставить пакет NIO, который предоставляет ту же функциональность, но со значительными улучшениями .
Затем мы рассмотрели оба API. На примерах мы научились мигрировать между ними. Мы также узнали, что java.io.File
теперь считается устаревшим и не рекомендуется для новых проектов . Тем не менее, нет никакого плана, чтобы устареть и удалить его.
Как всегда, все фрагменты кода из этой статьи доступны на GitHub .