5 操作文件

Wu Jun 2018-12-18 21:53:11
05 Java > 00 Java 基础 > 09 IO

Path 接口和 Files 类封装了在用户机器上处理文件系统所需的所有功能,他们是在 Java SE 7 中新添加进来的,比自 JDK1.0 以来一直使用的 File 类方便很多。

1 Path

Path 表示的是一个目录名序列,其后还可以跟着一个文件名。

路径中的第一个部件可以是根部件,例如 /C:\。以根部件开始的路径是绝对路径;否则,就是相对路径。

Path absolute = Paths.get("/home","harry");
Path relative = Paths.get("myprog","conf","user.properties");

静态的 Paths.get 方法接受一个或多个字符串,并将它们用默认文件系统的路径分隔符(/,\)连接起来。

1.1 绝对路径(resolve)

组合或解析路径,调用 p.resolve(q) 将按照下列规则返回一个路径:

1.2 绝对兄弟路径(resolveSibling)

解析指定路径的父路径产生其兄弟路径

Path workPath = Paths.get("/opt/myapp/work");
Path tempPath = workPath.resolveSibling("temp");
//tempPath == /opt/myapp/temp.

1.3 相对路径(relativize)

resolve 的对立面,即调用 p.relativize® 将产生路径 q,而对 q 进行的解析的结果正是 r。

例如,以“/home/cay”为目标对“/home/fred/myprog”进行相对化操作,会产生“…/fred/yprog",其中假设 .. 表示的是文件系统的父目录。

1.4 规范化(normalize)

移除所有冗余的 ... 部件(或者文件系统认为冗余的所有部件)。

例如,规范化“/home/cay/…/fred/./myprog”将产生“/home/fred/myprog”。

1.5 根目录绝对路径(toAbsolutePath)

产生给定路径的绝对路径,该绝对路径从根目录开始。

例如“/home/fred/input.txt”或“c:\Usersfredinput.txt”。

1.6 断开路径

Path 类有许多有用的方法用来将路径断开。

Path p = Paths.get("/home","fred","myproperties");
Path parent = p.getParent();
Path file = p.getFileName();
Path root = p.getRoot();

1.7 Scanner

还可以从 Path 对象中构建 Scanner 对象:

Scanner in = new Scanner(Paths.get("/home/fred/input.txt"));

1.7 遗留系统

需要与遗留系统交互时,可以使用 Path 的 toFile 方法,或者 File 类的 toPath 方法

2 Files

2.1 读写文件

Files 类可以使得普通文件操作变得快捷。

1)读
2)写
3)大文本

Files 类的简便方法适用于处理中等长度的文本文件,如果要处理的文本长度较大,或者是二进制文件,还是应该使用所熟知的输入输出流或者读入器、写出器。

InputStream in = Files.newInputStream(path);
OutputStream out = Files.newOutputStream(path);
Reader in = Files.newBufferedReader(path, charset);
Writer out = Files.newBufferedWriter(path, charset);

2.2 创建文件和目录

1)创建新目录

中间目录必须是已存在

Files.createDirectory(path);

同时创建中间目录

Files.createDirectories(path);
2)创建空文件

如果文件已存在,会抛异常。

Files.createFile(path);

检查文件是否存在和创建文件是原子性的,如果文件不存在,该文件就会被创建,并且其他程序在此过程中是无法执行文件创建操作的。

3)创建临时文件和临时目录
Path newPath = Files.createTempFile(dir,prefix,suffix);
Path newPath = Files.createTempFile(prefix,suffix);
Path newPath = Files.createTempDirectory(dir,prefix);
Path newPath = Files.createTempDirectory(prefix);

其中,dir 是一个 Path 对象,prefix 和 suffix 是可以为 null 的字符串。例如,调用 Files.createTempFile(null, “.txt”) 可能会返回一个像“/tmp/1234405522364837194.txt”这样的路径。

创建文件或目录,可以制定属性,例如文件的拥有者和权限。

2.3 复制、移动和删除文件

1)复制

StandardCopyOption

2)移动

如果目标路径已经存在,那么复制或移动将失败。

Files.move(fromPath,toPath);
3)删除
Files.delete(path);

如果要删除的文件不存在,会抛异常。

boolean deleted = Files.deleteIfExits(path);

2.4 获取文件信息

1)路径属性
2)文件字节数

size方法

long filesize = Files.size(path);
3)文件拥有者

getOwner 方法将文件的拥有者作为 java.nio.file.attribute.UserPrincipal 的一个实例返回。

4)基本属性集

获取基本属性集

BasicFileAttributes attributes = Files .readAttributes(path,BasicFileAttributes.class);

如果文件系统兼容 POSIX,可获取 PosixFileAttributes 实例:

PosixFileAttributes attributes = Files .readAttributes(path,PosixFilesAttributes.class);

然后从中找到拥有者,以及文件的拥有者、组或访问权限。

2.5 访问目录中的项

1)list

Files.list 方法会返回一个可以读取目录中各个项的 Stream 对象。惰性读取,更高效。

list 方法不会进入子目录。

try( Stream<Path> entries = Files.list(pathToDirectory){...}
2)walk

Files.walk 方法会产生一个可以遍历目录中所有子目录的 Stream 对象。

try( Stream<Path> entries = Files.walk方法(pathToRoot){...}

限制想要访问的树的深度。

File.walk(pathToRoot, depth)

2.6 使用目录流

要对遍历过程进行更加细粒度的控制,应该使用 File.newDirectoryStream 对象,它会产生一个 DirectoryStream。

1)DirectoryStream

DirectoryStream 不是 java.util.stream.Stream 的子接口,而是专门用于目录遍历的接口。它是 Iterable 的子接口,可以在增强的 for 循环中使用目录流。

try (DirectoryStream<Path> entries = Files.newDirectoryStream(dir)){
    for (Path entry: entries){
        Process entries
    }
}

访问目录中的 项并没有具体的顺序。

2)过滤文件

可以用 glob 模式来过滤文件:

try (DirectoryStream<Path> entries = Files.newDirectoryStream(dir,"*.java"))

2.7 ZIP 文件系统

1)建立文件系统
FileSystem fs = FileSystem.newFileSystem(Path.get(zipname),null);
2)复制文件
Files.copy(fs.getPath(soureceName),targetPath);

fs.getPath 与 Paths.get 类似

3)遍历文件树
FileSystem fs = FileSystem.newFileSystem(Path.get(zipname),null);
Files.walkFileTreee(fs.getPath("/"),new SimpleFileVisitor<Path>(){
    public FileVisitResult visitFile(Path file,BasicFileAttributes attrs) throws IOException{
        System.out.pintln(file);
        return FileVisitResult.CONTINUE;
    }
});