Причина, по которой Java занимает первое место в списке языков программирования, заключается в его мощной и богатой библиотеке классов, в которой можно найти решение практически для всех проблем программирования. А вот в более ранних версиях потоки ввода-вывода (I/O) были не так приятны для разработчиков:
1) ввод-вывод до JDK 1.4 не имеет концепции буферов, не поддерживает регулярные выражения, поддерживает кодировку с ограниченным набором символов и т. д.; 2) JDK 1.4 представил неблокирующий ввод-вывод, который представляет собой NIO 1.0, но с ним сложно перемещаться по каталогам, не поддерживаются неблокирующие операции файловой системы и т. д.
Чтобы обойти эти ограничения, в JDK 1.7 был представлен новый NIO, которому посвящена эта статья, — NIO 2.0.
01. Краеугольный камень: Путь
Путь может представлять либо каталог, либо файл, точно так же, как Файл — конечно, Путь используется для замены Файла.
1) может пройтиPaths.get()
Создайте объект Path, в настоящее время Path фактически не создается на физическом диске, параметр может быть либо именем файла, либо именем каталога, может использоваться абсолютный или относительный путь.
2) может пройтиFiles.notExists()
Проверьте, существует ли путь (каталог или файл).
3) может пройтиFiles.createDirectory()
Создайте каталог.К этому моменту каталог успешно создан на физическом диске и может быть просмотрен через диспетчер ресурсов.
4) может пройтиFiles.createFile()
Создайте файл.На данный момент файл успешно создан на физическом диске и может быть просмотрен через диспетчер ресурсов.
5) может пройтиtoAbsolutePath()
См. Путь для абсолютного пути.
6) может пройтиresolve()
Concatenate Path, параметр может быть новым объектом Path или соответствующей строкой.
Конкретный код выглядит следующим образом:
public class Wanger {
public static void main(String[] args) {
// 相对路径
Path dir = Paths.get("chenmo");
// 输出 dir 的绝对路径
System.out.println(dir.toAbsolutePath()); // 输出:D:\program\java.git\java_demo\chenmo
if (Files.notExists(dir)) {
try {
// 如果目录不存在,则创建目录
Files.createDirectory(dir);
} catch (IOException e1) {
e1.printStackTrace();
}
}
// 这时候 chenmo.txt 文件并未创建
// 通过 resolve 方法把 dir 和 chenmo.txt 链接起来
Path file = dir.resolve("chenmo.txt");
// 输出 file 的绝对路径
System.out.println(file.toAbsolutePath()); // 输出:D:\program\java.git\java_demo\chenmo\chenmo.txt
if (Files.notExists(file)) {
try {
// 如果文件不存在,则创建文件
Files.createFile(file);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Если вы хотите преобразовать файл в путь, вы можете передать класс FiletoPath()
метод завершен. Пример кода выглядит следующим образом:
File file = new File("沉默王二.txt");
Path path = file.toPath();
Если вы хотите преобразовать путь в файл, вы можете передать класс путиtoFile()
метод завершен. Пример кода выглядит следующим образом:
Path path = Paths.get("沉默王二.txt");
File file = path.toFile();
02. Каталог процессов
Новое в NIO 2.0java.nio.file.DirectoryStream<T>
Интерфейс может быть очень удобным для поиска файлов (соответствующих определенным правилам) в каталоге.Например, мы хотим найти файлы с суффиксом txt в каталоге chenmo.Пример кода выглядит следующим образом:
// 相对路径
Path dir = Paths.get("chenmo");
try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, "*.txt")) {
for (Path entry : stream) {
System.out.println(entry.getFileName());
}
} catch (IOException e) {
e.printStackTrace();
}
1)Files.newDirectoryStream(Path dir, String glob)
Возвращает отфильтрованный DirectoryStream (поток каталога), первый параметр — это каталог, а второй параметр — это универсальное выражение, например*.txt
Представляет все файлы с суффиксом txt.
2) Так как DirectoryStream наследует интерфейс Closeable, он может писать более безопасный код с синтаксисом try-with-resources Поток каталога автоматически вызовет метод close, чтобы закрыть поток и освободить ресурсы, связанные с потоком, поэтому в этом нет необходимости. взять на себя инициативу, наконец, закрытие.
3) DirectoryStream известен как поток каталогов и позволяет удобно использовать конструкции for-each для обхода каталогов.
03. Обработать дерево каталогов
Дерево каталогов означает, что в каталоге есть как файлы, так и подкаталоги, либо их нет, либо одно или другое. NIO 2.0 может легко перемещаться по дереву каталогов и работать с соответствующими файлами; одним из ключевых методов является walkFileTree класса Files, который определяется следующим образом:
public static Path walkFileTree(Path start, FileVisitor<? super Path> visitor)
throws IOException
{
return walkFileTree(start,
EnumSet.noneOf(FileVisitOption.class),
Integer.MAX_VALUE,
visitor);
}
Второй параметр, FileVisitor, называется интерфейсом доступа к файлам. Его очень сложно реализовать. Есть 5 методов для реализации, но, к счастью, разработчик JDK предоставляет класс реализации по умолчанию SimpleFileVisitor. Если мы хотим найти только из каталога суффикс txt дерева, вы можете сделать это:
// 相对路径
Path dir = Paths.get("chenmo");
try {
Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
if (file.toString().endsWith(".txt")) {
System.out.println(file.getFileName());
}
return FileVisitResult.CONTINUE;
}
});
} catch (IOException e) {
e.printStackTrace();
}
Переопределите метод VisitFile SimpleFileVisitor, создав анонимный внутренний класс, и распечатайте его, если суффикс равен txt.
04. Удаление, копирование и перемещение файлов
Создать файл очень просто. Мы уже сталкивались с этим раньше, поэтому удалить файл так же просто. Пример кода выглядит следующим образом:
Files.delete(file);
Files.deleteIfExists(file);
использоватьFiles.delete()
Лучше всего использовать перед удалением файловFiles.exists()
Определите, существует ли файл, иначе будет выброшено исключение NoSuchFileException;Files.deleteIfExists()
не надо.
Копирование файлов не сложное, пример кода такой:
Path source = Paths.get("沉默王二.txt");
Path target = Paths.get("沉默王二1.txt");
Files.copy(source, target);
Перемещение файла очень похоже на копирование файла, пример кода следующий:
Path source = Paths.get("沉默王二.txt");
Path target = Paths.get("沉默王二1.txt");
Files.move(source, target);
05. Быстро читайте и записывайте файлы
NIO 2.0 предоставляет вспомогательные методы чтения и записи с буферами, которые также очень просты в использовании. в состоянии пройтиFiles.newBufferedWriter()
Получите буферизованный входной поток файла и передайтеwrite()
метод для записи данных; затем передатьFiles.newBufferedReader()
Получить выходной поток буферизованного файла черезreadLine()
способ чтения данных. Пример кода выглядит следующим образом.
Path file = Paths.get("沉默王二.txt");
try (BufferedWriter writer = Files.newBufferedWriter(file, StandardCharsets.UTF_8)) {
writer.write("一个有趣的程序员");
} catch (Exception e) {
e.printStackTrace();
}
try (BufferedReader reader = Files.newBufferedReader(file, StandardCharsets.UTF_8)) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (Exception e) {
e.printStackTrace();
}
06. Важно: асинхронные операции ввода-вывода
Давайте будем честными, упомянутые выше — это приятные моменты NIO 2.0, а асинхронные операции ввода-вывода (также известные как AIO) — это то, что действительно важно. Асинхронные операции ввода-вывода могут в полной мере использовать характеристики многоядерных процессоров, и нет необходимости запускать поток для обработки ввода-вывода, как раньше, чтобы не блокировать другие операции основного потока.
Основная концепция асинхронных операций ввода-вывода состоит в том, чтобы инициировать неблокирующую операцию ввода-вывода и уведомить, когда операция ввода-вывода завершена. Его можно разделить на две формы: Future и Callback. Если мы хотим, чтобы основной поток инициировал операцию ввода-вывода и ждал результата в циклическом режиме, мы обычно используем форму Future; а основная идея обратного вызова заключается в том, что основной поток отправляет разведчик ( CompletionHandler) в отдельный поток для выполнения операций ввода-вывода. Когда это сделано, запускается завершенный или неудачный метод инспектора.
1) Будущее
Сначала рассмотрим пример, код выглядит следующим образом:
public static void main(String[] args) throws IOException, InterruptedException, ExecutionException {
Path file = Paths.get("沉默王二.txt");
AsynchronousFileChannel channel = AsynchronousFileChannel.open(file);
Future<Integer> result = channel.read(ByteBuffer.allocate(100_000), 0);
while (!result.isDone()) {
System.out.println("主线程继续做事情");
}
Integer bytesRead = result.get();
System.out.println(bytesRead);
}
1) пройтиAsynchronousFileChannel.open()
Открывает канал асинхронного файлового канала.
2) Используйте Future, чтобы сохранить результат, считанный с канала.
3) пройтиisDone()
Циклический перебор, чтобы определить, завершена ли операция асинхронного ввода-вывода, если нет, основной поток может продолжать выполнять свои собственные задачи.
2) Обратный звонок
Сначала рассмотрим пример, код выглядит следующим образом:
public static void main(String[] args) throws IOException, InterruptedException, ExecutionException {
Path file = Paths.get("沉默王二.txt");
AsynchronousFileChannel channel = AsynchronousFileChannel.open(file);
channel.read(ByteBuffer.allocate(100_000), 0, null, new CompletionHandler<Integer, ByteBuffer>() {
public void completed(Integer result, ByteBuffer attachment) {
System.out.println(result);
}
public void failed(Throwable exc, ByteBuffer attachment) {
System.out.println(exc.getMessage());
}
});
System.out.println("主线程继续做事情");
}
1) пройтиAsynchronousFileChannel.open()
Открывает канал асинхронного файлового канала.
2) Включите CompletionHandler в форме анонимного внутреннего класса в методе чтения, а затем реализуйте два метода прослушивания CompletionHandler, распечатайте результат при завершении и распечатайте информацию об исключении при сбое.
Независимо от того, в форме ли это Future или Callback, асинхронный ввод-вывод — это мощная функция, которая гарантирует, что производительность не будет значительно снижена при работе с большими файлами.
07. Наконец
Добро пожаловать в официальную учетную запись «Silent King II» и ответьте на ключевое слово «java» в фоновом режиме, чтобы бесплатно получить «Материалы для продвинутых программистов на Java».