好的,各位亲爱的程序员朋友们,欢迎来到“Java NIO.2:文件系统API”的探险之旅!准备好了吗?让我们一起扬帆起航,拨开迷雾,揭开Java NIO.2文件系统API的神秘面纱。
开场白:文件,程序员的“老朋友” 🤝
在程序员的世界里,文件就像我们形影不离的老朋友,存储着代码、数据、配置,承载着我们的智慧和汗水。从最初的简单文本文件,到复杂的二进制文件、数据库文件,我们无时无刻不在和它们打交道。然而,传统的Java IO操作,就像老牛拉破车,效率低下,阻塞式操作让我们的程序“卡顿”不堪。
终于,Java NIO.2(New IO 2)带着革命性的文件系统API闪亮登场,它像一辆法拉利跑车,让我们在文件操作的道路上风驰电掣,体验前所未有的速度与激情!🚀
第一站:NIO.2 核心概念速览 🗺️
在深入探索之前,我们先来一张“藏宝图”,了解NIO.2文件系统API中的几个关键概念:
| 概念 | 解释 | 备注 |
|---|---|---|
Path |
代表文件或目录的路径,是java.nio.file包下的接口,取代了java.io.File。它不仅仅是一个字符串,而是一个对象,包含更多信息和操作。 |
想象一下,Path就像一个指向宝藏的罗盘,指引我们找到文件或目录。 |
FileSystem |
代表文件系统的抽象,可以通过FileSystems.getDefault()获取默认文件系统。 |
FileSystem就像一个国家,包含各种文件和目录,而Path就是这个国家的地址。 |
FileStore |
代表文件系统的存储设备,例如硬盘、U盘、网络共享等。 | FileStore就像一个仓库,存储着我们的文件。 |
WatchService |
允许我们监控文件或目录的变化,例如创建、删除、修改等。 | WatchService就像一个警卫,时刻守护着我们的文件,一旦发生变化,立刻通知我们。 |
DirectoryStream |
用于遍历目录中的文件,可以过滤文件类型。 | DirectoryStream就像一个探险家,带着我们深入目录,寻找我们需要的宝藏。 |
Files |
提供各种静态方法,用于文件和目录的操作,例如创建、删除、复制、移动、读取、写入等。 | Files就像一个工具箱,里面装满了各种工具,帮助我们轻松完成文件操作。 |
AsynchronousFileChannel |
异步文件通道,用于执行异步的文件读写操作,避免阻塞主线程。 | AsynchronousFileChannel就像一个快递员,悄悄地帮我们处理文件读写,不会打扰我们的工作。 |
FileVisitor |
用于遍历文件树,可以自定义遍历逻辑。 | FileVisitor就像一个导游,带着我们游览整个文件树,我们可以自定义游览路线和景点。 |
AclFileAttributeView |
用于管理文件的访问控制列表(ACL),控制不同用户的访问权限。 | AclFileAttributeView就像一个门卫,控制谁可以进入我们的文件,保障文件的安全。 |
第二站:Path:文件路径的“新宠” 💖
java.nio.file.Path接口是NIO.2文件系统API的核心,它取代了java.io.File。Path不仅仅是一个字符串,而是一个对象,包含更多信息和操作。
-
创建
Path对象-
Paths.get(String first, String... more):从字符串创建Path对象。Path path = Paths.get("C:", "Users", "username", "Documents", "myfile.txt"); // Windows Path path2 = Paths.get("/home", "username", "documents", "myfile.txt"); // Linux/macOS -
FileSystem.getPath(String first, String... more):从文件系统创建Path对象。FileSystem fileSystem = FileSystems.getDefault(); Path path3 = fileSystem.getPath("myfile.txt");
-
-
Path的常用方法方法 描述 示例 getFileName()返回 Path表示的文件或目录的名称。Path path = Paths.get("/home/user/myfile.txt"); String fileName = path.getFileName().toString(); // fileName = "myfile.txt"getParent()返回 Path的父路径。Path path = Paths.get("/home/user/myfile.txt"); Path parent = path.getParent(); // parent = "/home/user"getRoot()返回 Path的根路径。Path path = Paths.get("/home/user/myfile.txt"); Path root = path.getRoot(); // root = "/"getNameCount()返回 Path中名称元素的数量。Path path = Paths.get("/home/user/myfile.txt"); int count = path.getNameCount(); // count = 3getName(int index)返回 Path中指定索引位置的名称元素。Path path = Paths.get("/home/user/myfile.txt"); Path name = path.getName(0); // name = "home"subpath(int beginIndex, int endIndex)返回 Path中指定范围的子路径。Path path = Paths.get("/home/user/myfile.txt"); Path sub = path.subpath(0, 2); // sub = "home/user"isAbsolute()判断 Path是否是绝对路径。Path path = Paths.get("/home/user/myfile.txt"); boolean absolute = path.isAbsolute(); // absolute = truetoAbsolutePath()返回 Path的绝对路径。Path path = Paths.get("myfile.txt"); Path absolutePath = path.toAbsolutePath(); // 返回绝对路径normalize()规范化 Path,移除冗余的名称元素(例如.和..)。Path path = Paths.get("/home/user/.././myfile.txt"); Path normalized = path.normalize(); // normalized = "/home/myfile.txt"resolve(Path other)将 Path解析为另一个Path的相对路径。Path path = Paths.get("/home/user"); Path other = Paths.get("myfile.txt"); Path resolved = path.resolve(other); // resolved = "/home/user/myfile.txt"relativize(Path other)返回一个 Path,它是Path到另一个Path的相对路径。Path path = Paths.get("/home/user"); Path other = Paths.get("/home/user/myfile.txt"); Path relative = path.relativize(other); // relative = "myfile.txt"toUri()将 Path转换为URI。Path path = Paths.get("/home/user/myfile.txt"); URI uri = path.toUri(); // uri = "file:///home/user/myfile.txt"toFile()将 Path转换为File。Path path = Paths.get("/home/user/myfile.txt"); File file = path.toFile();示例代码
import java.nio.file.Path; import java.nio.file.Paths; public class PathExample { public static void main(String[] args) { Path path = Paths.get("/home/user/documents/myfile.txt"); System.out.println("File Name: " + path.getFileName()); System.out.println("Parent: " + path.getParent()); System.out.println("Root: " + path.getRoot()); System.out.println("Name Count: " + path.getNameCount()); System.out.println("Absolute Path: " + path.toAbsolutePath()); System.out.println("URI: " + path.toUri()); } }
第三站:Files:文件操作的“瑞士军刀” 🧰
java.nio.file.Files类提供了大量的静态方法,用于文件和目录的操作,就像一个百宝箱,里面装满了各种工具,帮助我们轻松完成文件操作。
-
文件和目录的创建与删除
createDirectory(Path dir, FileAttribute<?>... attrs):创建目录。createDirectories(Path dir, FileAttribute<?>... attrs):创建多级目录。createFile(Path file, FileAttribute<?>... attrs):创建文件。delete(Path path):删除文件或目录(如果目录为空)。deleteIfExists(Path path):如果文件或目录存在,则删除。
-
文件的复制与移动
copy(Path source, Path target, CopyOption... options):复制文件或目录。move(Path source, Path target, CopyOption... options):移动文件或目录。
CopyOption和StandardCopyOptionREPLACE_EXISTING:如果目标文件已存在,则替换它。COPY_ATTRIBUTES:复制文件属性(例如最后修改时间)。ATOMIC_MOVE:原子性地移动文件(如果文件系统支持)。
-
文件的读取与写入
readAllBytes(Path path):将文件内容读取到字节数组中。readAllLines(Path path, Charset charset):将文件内容读取到字符串列表中。write(Path path, byte[] bytes, OpenOption... options):将字节数组写入文件。write(Path path, Iterable<? extends CharSequence> lines, Charset charset, OpenOption... options):将字符串列表写入文件。
OpenOption和StandardOpenOptionAPPEND:追加到文件末尾。CREATE:如果文件不存在,则创建它。CREATE_NEW:如果文件已存在,则抛出异常。TRUNCATE_EXISTING:将文件截断为0字节。
-
文件属性的访问
getAttribute(Path path, String attribute, LinkOption... options):获取文件属性。setAttribute(Path path, String attribute, Object value, LinkOption... options):设置文件属性。getFileAttributeView(Path path, Class<V> type, LinkOption... options):获取文件属性视图。
-
其他常用方法
exists(Path path, LinkOption... options):判断文件或目录是否存在。notExists(Path path, LinkOption... options):判断文件或目录是否不存在。isDirectory(Path path, LinkOption... options):判断是否是目录。isRegularFile(Path path, LinkOption... options):判断是否是普通文件。isSymbolicLink(Path path):判断是否是符号链接。isReadable(Path path):判断是否可读。isWritable(Path path):判断是否可写。isExecutable(Path path):判断是否可执行。size(Path path):返回文件大小。getLastModifiedTime(Path path, LinkOption... options):返回最后修改时间。setLastModifiedTime(Path path, FileTime time):设置最后修改时间。getOwner(Path path, LinkOption... options):返回文件所有者。setOwner(Path path, UserPrincipal owner):设置文件所有者。
示例代码
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
public class FilesExample {
public static void main(String[] args) {
Path file = Paths.get("myfile.txt");
try {
// 创建文件
Files.createFile(file);
// 写入数据
List<String> lines = Arrays.asList("Hello", "World!");
Files.write(file, lines, StandardCharsets.UTF_8);
// 读取数据
List<String> readLines = Files.readAllLines(file, StandardCharsets.UTF_8);
System.out.println("Read lines: " + readLines);
// 获取文件大小
long size = Files.size(file);
System.out.println("File size: " + size);
// 删除文件
Files.delete(file);
} catch (IOException e) {
e.printStackTrace();
}
}
}
第四站:WatchService:文件监控的“千里眼” 👁️
java.nio.file.WatchService允许我们监控文件或目录的变化,例如创建、删除、修改等。它就像一个警卫,时刻守护着我们的文件,一旦发生变化,立刻通知我们。
-
创建
WatchServiceWatchService watchService = FileSystems.getDefault().newWatchService(); -
注册
Path到WatchServicePath directory = Paths.get("/home/user/documents"); directory.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE, StandardWatchEventKinds.ENTRY_MODIFY);StandardWatchEventKindsENTRY_CREATE:文件或目录被创建。ENTRY_DELETE:文件或目录被删除。ENTRY_MODIFY:文件或目录被修改。OVERFLOW:事件可能丢失或被丢弃。
-
监听事件
while (true) { WatchKey key; try { key = watchService.take(); } catch (InterruptedException e) { return; } for (WatchEvent<?> event : key.pollEvents()) { WatchEvent.Kind<?> kind = event.kind(); if (kind == StandardWatchEventKinds.OVERFLOW) { continue; } WatchEvent<Path> ev = (WatchEvent<Path>) event; Path filename = ev.context(); System.out.println(kind.name() + ": " + filename); } boolean valid = key.reset(); if (!valid) { break; } }
示例代码
import java.io.IOException;
import java.nio.file.*;
public class WatchServiceExample {
public static void main(String[] args) throws IOException, InterruptedException {
Path directory = Paths.get("/tmp/watchtest");
if (!Files.exists(directory)) {
Files.createDirectory(directory);
}
WatchService watchService = FileSystems.getDefault().newWatchService();
directory.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE, StandardWatchEventKinds.ENTRY_MODIFY);
System.out.println("Watching directory: " + directory);
while (true) {
WatchKey key;
try {
key = watchService.take();
} catch (InterruptedException e) {
return;
}
for (WatchEvent<?> event : key.pollEvents()) {
WatchEvent.Kind<?> kind = event.kind();
if (kind == StandardWatchEventKinds.OVERFLOW) {
continue;
}
WatchEvent<Path> ev = (WatchEvent<Path>) event;
Path filename = ev.context();
System.out.println(kind.name() + ": " + filename);
}
boolean valid = key.reset();
if (!valid) {
break;
}
}
}
}
第五站:AsynchronousFileChannel:异步IO的“闪电侠” ⚡
java.nio.channels.AsynchronousFileChannel允许我们执行异步的文件读写操作,避免阻塞主线程。它就像一个快递员,悄悄地帮我们处理文件读写,不会打扰我们的工作。
-
创建
AsynchronousFileChannelPath file = Paths.get("myfile.txt"); AsynchronousFileChannel channel = AsynchronousFileChannel.open(file, StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE); -
异步读取数据
ByteBuffer buffer = ByteBuffer.allocate(1024); channel.read(buffer, 0, buffer, new CompletionHandler<Integer, ByteBuffer>() { @Override public void completed(Integer result, ByteBuffer attachment) { System.out.println("Read " + result + " bytes"); attachment.flip(); byte[] data = new byte[attachment.limit()]; attachment.get(data); System.out.println(new String(data)); try { channel.close(); } catch (IOException e) { e.printStackTrace(); } } @Override public void failed(Throwable exc, ByteBuffer attachment) { System.err.println("Read failed: " + exc.getMessage()); try { channel.close(); } catch (IOException e) { e.printStackTrace(); } } }); -
异步写入数据
ByteBuffer buffer = ByteBuffer.wrap("Hello, Asynchronous World!".getBytes()); channel.write(buffer, 0, buffer, new CompletionHandler<Integer, ByteBuffer>() { @Override public void completed(Integer result, ByteBuffer attachment) { System.out.println("Written " + result + " bytes"); try { channel.close(); } catch (IOException e) { e.printStackTrace(); } } @Override public void failed(Throwable exc, ByteBuffer attachment) { System.err.println("Write failed: " + exc.getMessage()); try { channel.close(); } catch (IOException e) { e.printStackTrace(); } } });
示例代码
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.channels.CompletionHandler;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
public class AsynchronousFileChannelExample {
public static void main(String[] args) throws IOException, InterruptedException {
Path file = Paths.get("asyncfile.txt");
AsynchronousFileChannel channel = AsynchronousFileChannel.open(file, StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE);
ByteBuffer buffer = ByteBuffer.wrap("Hello, Asynchronous World!".getBytes());
channel.write(buffer, 0, buffer, new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer result, ByteBuffer attachment) {
System.out.println("Written " + result + " bytes");
ByteBuffer readBuffer = ByteBuffer.allocate(1024);
channel.read(readBuffer, 0, readBuffer, new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer result, ByteBuffer attachment) {
System.out.println("Read " + result + " bytes");
attachment.flip();
byte[] data = new byte[attachment.limit()];
attachment.get(data);
System.out.println(new String(data));
try {
channel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
System.err.println("Read failed: " + exc.getMessage());
try {
channel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
System.err.println("Write failed: " + exc.getMessage());
try {
channel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
// 保持程序运行,直到异步操作完成
Thread.sleep(2000);
}
}
总结:NIO.2,文件操作的未来! 🚀
Java NIO.2文件系统API为我们带来了全新的文件操作体验,它更加灵活、高效、易用,让我们能够更好地管理和操作文件。从Path到Files,从WatchService到AsynchronousFileChannel,NIO.2提供了丰富的工具和API,帮助我们轻松应对各种文件操作场景。
希望通过这次探险之旅,你已经对Java NIO.2文件系统API有了更深入的了解。现在,拿起你的键盘,开始使用NIO.2,让你的文件操作飞起来吧!
记住,NIO.2不仅仅是一个API,更是一种思想,一种拥抱未来的态度。让我们一起学习、探索、进步,共同迎接更加美好的编程未来! 💻🎉