Java7之后提供了全面的文件IO和文件系统访问支持,并且还支持异步的Channel
NIO.2引入了一个Path接口,Path接口代表一个平台无关的平台路径,此外NIO.2还提供了Files和Paths两个工具类,其中Files包含了大量静态的工具类方法来操作文件,Paths则包含了两个返回Path的静态工厂方法
import java.io.*;
import java.net.*;
import java.nio.file.*;
public class PathTest
{
public static void main(String[] args)
throws Exception
{
// 以当前路径来创建Path对象
Path path = Paths.get(".");
System.out.println("path里包含的路径数量:"
+ path.getNameCount());
System.out.println("path的根路径:" + path.getRoot());
// 获取path对应的绝对路径。
Path absolutePath = path.toAbsolutePath();
System.out.println(absolutePath);
// 获取绝对路径的根路径
System.out.println("absolutePath的根路径:"
+ absolutePath.getRoot());
// 获取绝对路径所包含的路径数量
System.out.println("absolutePath里包含的路径数量:"
+ absolutePath.getNameCount());
System.out.println(absolutePath.getName(3));
// 以多个String来构建Path对象
Path path2 = Paths.get("g:", "publish", "codes");
System.out.println(path2);
}
}
import java.nio.file.*;
import java.nio.charset.*;
import java.io.*;
import java.util.*;
public class FilesTest
{
public static void main(String[] args)
throws Exception
{
// 复制文件
Files.copy(Paths.get("FilesTest.java"),
new FileOutputStream("a.txt"));
// 判断FilesTest.java文件是否为隐藏文件
System.out.println("FilesTest.java是否为隐藏文件:"
+ Files.isHidden(Paths.get("FilesTest.java")));
// 一次性读取FilesTest.java文件的所有行
List<String> lines = Files.readAllLines(Paths
.get("FilesTest.java"), Charset.forName("gbk"));
System.out.println(lines);
// 判断指定文件的大小
System.out.println("FilesTest.java的大小为:"
+ Files.size(Paths.get("FilesTest.java")));
List<String> poem = new ArrayList<>();
poem.add("水晶潭底银鱼跃");
poem.add("清徐风中碧竿横");
// 直接将多个字符串内容写入指定文件中
Files.write(Paths.get("pome.txt"), poem,
Charset.forName("gbk"));
// 使用Java 8新增的Stream API列出当前目录下所有文件和子目录
Files.list(Paths.get(".")).forEach(path -> System.out.println(path));
// 使用Java 8新增的Stream API读取文件内容
Files.lines(Paths.get("FilesTest.java"), Charset.forName("gbk"))
.forEach(line -> System.out.println(line));
FileStore cStore = Files.getFileStore(Paths.get("C:"));
// 判断C盘的总空间,可用空间
System.out.println("C:共有空间:" + cStore.getTotalSpace());
System.out.println("C:可用空间:" + cStore.getUsableSpace());
}
}
Files类提供了如下两个方法来遍历文件和子目录:
- walkFileTree(Path start, FileVisitor super Path> visitor): 遍历start路径下的所有文件和子目录
- walkFileTree(Path start, Set< FileVisitOption > options, int maxDepth, FileVisitor super Path>visitor): 该方法跟上一个类似,但最多遍历maxDepth深度的文件
两个方法都需要FileVisitor参数,FileVisitor代表一个文件访问器,walkFileTree()方法会自动遍历start路径下的所有文件和子目录,遍历文件和子目录都会触发FileVisitor中相应的方法
FileVisitor中定义了如下4个方法:
这4个方法都返回一个FileVisitResult对象,它是一个枚举类,代表访问了之后的后续行为(FileVisitResult):
实际编程时,可以通过继承SimpleFileVisitor(FileVisitor的实现类)来实现自己的文件访问器
import java.io.*;
import java.nio.file.*;
import java.nio.file.attribute.*;
public class FileVisitorTest
{
public static void main(String[] args)
throws Exception
{
// 遍历g:\publish\codes\15目录下的所有文件和子目录
Files.walkFileTree(Paths.get("g:", "publish", "codes", "15"),
new SimpleFileVisitor<Path>()
{
// 访问文件时候触发该方法
@Override
public FileVisitResult visitFile(Path file,
BasicFileAttributes attrs) throws IOException
{
System.out.println("正在访问" + file + "文件");
// 找到了FileInputStreamTest.java文件
if (file.endsWith("FileInputStreamTest.java"))
{
System.out.println("--已经找到目标文件--");
return FileVisitResult.TERMINATE;
}
return FileVisitResult.CONTINUE;
}
// 开始访问目录时触发该方法
@Override
public FileVisitResult preVisitDirectory(Path dir,
BasicFileAttributes attrs) throws IOException
{
System.out.println("正在访问:" + dir + " 路径");
return FileVisitResult.CONTINUE;
}
});
}
}
之前的实现方式是,启动一个后台线程监控文件,每隔一段时间去遍历一下指定目录的文件,如果发现结果不一样,则判定文件发生了变化,NIO.2的Path类提供了如下方法来监听文件系统的变化
如果程序需要一直监控,则应该选择使用take()方法,如果只需要监控指定时间则应该使用poll()方法
import java.io.*;
import java.nio.file.*;
import java.nio.file.attribute.*;
public class WatchServiceTest
{
public static void main(String[] args)
throws Exception
{
// 获取文件系统的WatchService对象
WatchService watchService = FileSystems.getDefault()
.newWatchService();
// 为C:盘根路径注册监听
Paths.get("C:/").register(watchService,
StandardWatchEventKinds.ENTRY_CREATE,
StandardWatchEventKinds.ENTRY_MODIFY,
StandardWatchEventKinds.ENTRY_DELETE);
while (true)
{
// 获取下一个文件改动事件
WatchKey key = watchService.take(); // ①
for (WatchEvent<?> event : key.pollEvents())
{
System.out.println(event.context() +" 文件发生了 "
+ event.kind()+ "事件!");
}
// 重设WatchKey
boolean valid = key.reset();
// 如果重设失败,退出监听
if (!valid)
{
break;
}
}
}
}
NIO.2在java.nio.file.attribute包下提供了大量的工具类,通过这些工具类可以很简单的读写文件属性,工具类大致分为两大类:
在这些工具类中,FileAttributeView是其他XxxAttributeView的父接口:
import java.io.*;
import java.util.*;
import java.nio.file.*;
import java.nio.*;
import java.nio.charset.*;
import java.nio.file.attribute.*;
public class AttributeViewTest
{
public static void main(String[] args)
throws Exception
{
// 获取将要操作的文件
Path testPath = Paths.get("AttributeViewTest.java");
// 获取访问基本属性的BasicFileAttributeView
BasicFileAttributeView basicView = Files.getFileAttributeView(
testPath, BasicFileAttributeView.class);
// 获取访问基本属性的BasicFileAttributes
BasicFileAttributes basicAttribs = basicView.readAttributes();
// 访问文件的基本属性
System.out.println("创建时间:" + new Date(basicAttribs
.creationTime().toMillis()));
System.out.println("最后访问时间:" + new Date(basicAttribs
.lastAccessTime().toMillis()));
System.out.println("最后修改时间:" + new Date(basicAttribs
.lastModifiedTime().toMillis()));
System.out.println("文件大小:" + basicAttribs.size());
// 获取访问文件属主信息的FileOwnerAttributeView
FileOwnerAttributeView ownerView = Files.getFileAttributeView(
testPath, FileOwnerAttributeView.class);
// 获取该文件所属的用户
System.out.println(ownerView.getOwner());
// 获取系统中guest对应的用户
UserPrincipal user = FileSystems.getDefault()
.getUserPrincipalLookupService()
.lookupPrincipalByName("guest");
// 修改用户
ownerView.setOwner(user);
// 获取访问自定义属性的FileOwnerAttributeView
UserDefinedFileAttributeView userView = Files.getFileAttributeView(
testPath, UserDefinedFileAttributeView.class);
List<String> attrNames = userView.list();
// 遍历所有的自定义属性
for (var name : attrNames)
{
ByteBuffer buf = ByteBuffer.allocate(userView.size(name));
userView.read(name, buf);
buf.flip();
String value = Charset.defaultCharset().decode(buf).toString();
System.out.println(name + "--->" + value);
}
// 添加一个自定义属性
userView.write("发行者", Charset.defaultCharset()
.encode("一块大洋"));
// 获取访问DOS属性的DosFileAttributeView
DosFileAttributeView dosView = Files.getFileAttributeView(testPath,
DosFileAttributeView.class);
// 将文件设置隐藏、只读
dosView.setHidden(true);
dosView.setReadOnly(true);
}
}