使用java.nio.Path和java.nio.Files重新编写java.io.File的代码
简要概述
鉴于之前的代码中我使用了java.io.File,因为冲动使用了Path和Files进行了替换,所以在更改现有代码的角度来介绍。对于已经熟练掌握NIO2的人来说,我认为阅读这篇文章不会有任何发现。
顺便说一下,据说自JDK7起,新的文件相关API被称为NIO2(新I/O 2),而无标记的则指的是1.4时代添加的通道(Channel)和字符集(Charset)。
背景资料
在File类中有以下两个功能。
-
- ファイルの置き場所を定義する
- ファイルを操作する
据说在JDK7的NIO2中,将其分割为以下几个部分。
-
- ファイルの置き場所を定義する……java.nio.file.Path インターフェイス
- ファイルを操作する……java.nio.file.Files
未来中,我不确定 File 类是否会被完全替换为 Path 和 Files。观察 File 类的 Javadoc,可以看到它在 1.7 中添加了 toPath() 方法,而在 1.8 中没有任何新方法。因此,可以推测未来的文件相关API的开发可能会转向 Files 和 Path。然而,在 JDK 中仍然存在许多库仅限于处理 File,而不是 Path。例如,JavaFX 的 FileChooser 和 Drag & Drop API 只能处理 File,如果想使用 Files 类进行操作,就必须使用 File 类的 toPath() 方法将其转换为 Path 对象。
如果您当前的代码使用的是java.io.File,并且测试代码也十分完善,考虑到Java的向后兼容性历史,没有必要强行将其转换为Path。如果由于情况迫使您在JDK6或更早的环境中进行开发,那么也没有必要转换。然而,由于Files类的功能更为优秀,对于新开发的部分,试着尝试使用NIO2来写,这是一个可行的选择。
请留意
NIO2 是从 JDK7 开始添加的。尽管被认为 Android SDK 中的 JDK7 库基本齐全,但遗憾的是,几乎没有实现 java.nio 包中的大部分类。
请参阅下面的文章以获取更详细的信息。
- Androidはどの程度 Java7か?
这篇文章没有提到的内容
这个库已经问世超过5年,关于Path和Files的详细用法以及从File转换的问题已经有很多优秀的文章,所以在本文中将省略与此无关的部分。
创建对象
对于文件的情况
我认为,通过将文件路径作为字符串(或URL)传递给构造函数生成文件是主要方法。
File file = new File("dir/file.txt");
在Path的情况下
有一个名为Paths的工厂,可以通过将字符串或URI作为get()方法的参数来创建对象。
Path path = Paths.get("dir/file.txt");
文件和路径的相互转换
File和Path之间可以相互转换。如果希望在不返回Path的库中使用NIO,可以使用这个方法将Path对象转换为File对象,就像前面提到的FileChooser一样。
文件 -> 路径 ->
Path path = file.toPath();
路径 -> 文件
File file = path.toFile();
获取文件的绝对路径
在文件的情况下
使用getAbsolutePath返回绝对路径的字符变量。
file.getAbsolutePath();
关于NIO2
将 toAbsolutePath 方法用于将相对路径转换为绝对路径的 Path 对象,然后通过 toString() 方法将其转换为字符串。
path.toAbsolutePath().toString(),
确认文件是否存在
在檔案的情況下
file.exists();
对于NIO2情况来说
Files.exists(path);
判断文件是否可读取
文件的情况下
使用File.canRead()。
Note: The given sentence is already in Java code, so there is no literal translation in Chinese. The provided response is the equivalent Chinese expression for using the method File.canRead().
file.canRead())
NIO2的情况下。
可以使用isReadable方法去判断文件是否可读。
Files.isReadable(Path)
创建文件夹
文件的情况下 de ɡ hù)
使用 File.mkdirs 可以一起创建父文件夹。它以布尔值形式返回成功与否。
new File("dir").mkdirs();
对于NIO2的情况来说
使用Files#createDirectories方法。由于该方法可能会抛出IOException,所以需要处理异常。
Files.createDirectories(dirPath);
判断文件夹或文件
没什么太大的变化。
如果是文件的情况
file.isDirectory()
在NIO2的情况下
Files.isDirectory(path)
将文件移动
文件的情况下
使用 File.renameTo 这个方法。它会返回一个布尔值来表示是否成功。
file.renameTo(dest);
关于NIO2的情况
您可以使用 Files#move 方法来实现,它将返回修改后文件的路径。
Files.move(path, destPath);
删除文件
对于文件的情况
new File("file.txt").delete();
在NIO2的情况下
Files.delete(Paths.get("file.txt"));
另外,还有一个名为 deleteIfExists 的方法,在存在文件时会删除文件,并返回一个布尔值。
Files.deleteIfExists(Paths.get("file.txt"));
操作文件夹内的所有文件
其实这个有点奇怪难度高。
如果是java.io.File的情况
如果你想操作位于名为dir的文件夹中的所有文件,可以使用java.io.File对象以数组形式获取代码如下:
File[] files = new File("dir").listFiles();
在NIO2的情况下
如果使用JDK8,使用Files#list(Path)函数就很简单。
Stream<Path> files = Files.list(Paths.get(articleDir));
如果需要的不是Stream而是List,那么就进行collect操作。
List<Path> files = Files.list(f).collect(Collectors.toList());
在JDK7中是否会使用Files.newDirectoryStream呢……
try (final DirectoryStream<Path> directoryStream
= Files.newDirectoryStream(dir, Articles::isValidContentPath)){
// ……
} catch (final IOException e) {
e.printStackTrace();
}
获取文件的最后更新日期和时间(以毫秒为单位)。
如果是文件的情况下
可以通过lastModified()方法获取毫秒数。
final long lastModifiedMs = file.lastModified();
对于NIO2的情况下
可以通过使用Files.getLastModifiedTime方法获取FileTime对象,之后将其转换为毫秒,就可以像以前一样获取最后修改日期时间。FileTime类提供了多种不同的转换方法,因此在编码阶段就能轻松避免“本以为是以秒为单位,结果却是以毫秒为单位”的常见问题。
Files.getLastModifiedTime(path).toMillis());
然而,与File#lastModified不同,getLastModifiedTime可能会引发IOException,因此需要处理异常。
文件的一些方便方法
我顺便介绍一些。
创建一个新的BufferedReader对象,用于读取指定路径下的文件。
在过去,您可能需要通过包装Reader对象来进行大量的初始化操作,或者可能需要使用自定义的FileUtils类来初始化FileReader对象并返回。您可能还会使用Apache Commons库。
new BufferedReader(new InputStreamReader(new FileInputStream(pTargetFileName), pEncode));
如果是关于文件和路径的情况,如果要读取的文件编码为 UTF-8,则可以使用以下方式。
final BufferedReader fileReader = Files.newBufferedReader(path)
通过在第二个参数中传递Charset,您可以处理使用不同编码的文件。
创建文件新的缓冲写入器。
当然还有Writer的方法。
final BufferedWriter writer = Files.newBufferedWriter(path);
读取所有行的文件。
可以读取文件的内容并逐行放入一个列表中进行获取。这种类型的方法也可以自己编写并反复使用,非常方便。需要进行IOException的异常处理。
final List<String> lines = Files.readAllLines(path);
读取文件#读取所有字节
这个方法用于将小文件读入一个字节数组中。
final byte[] bytes = Files.readAllBytes(path);
文件#写入
将字节数组的内容写入到指定路径的文件中。如果要将字符串str的内容输出到路径文件中,请按照以下方式进行。需要进行IOException的异常处理。
Files.write(path, str.getBytes(StandardCharsets.UTF_8.name()));
总结
我主要讨论了将现有的File代码替换为使用Path和Files的代码的方法。Files中有许多需要异常处理的方法,需要一个合适处理异常的编程风格。相比于File时,键入的字符数也会简单地增加,所以一开始可能会有些困难。遗憾的是,需要异常处理的方法与Lambda表达式的兼容性不太好。
另外,虽然这次没有提到,但 Files 类的方法大多数基于文件的编码为 UTF-8,请注意如果使用其他编码可能需要做一些困难的处理。
仅需一个选项,以下是以中文原生方式的释义:参考。
图书
『現場で使える[最新]Java SE 7/8 速攻入門』……NIO についての歴史や背景や意義、さらに使い方まで非常に詳しく紹介されています。
网络
-
- ファイル・ディレクトリ操作2
-
- 参考メモ/Java7のnio2のファイル操作の便利機能(basename,dirname,realpath相当とファイルの簡易読み書き)
- NIOでフォルダを再帰処理する方法メモ