File Operations
Files类是java.nio.file
包的另一个主要入口点。此类提供了一组丰富的静态方法,用于读取,写入和操作文件和目录。 Files
方法适用于Path
对象的实例。在 continue 其余部分之前,您应该熟悉以下常见概念:
释放系统资源
此 API 中使用的许多资源(例如流或通道)实现或扩展java.io.Closeableinterface。 Closeable
资源的要求是,在不再需要close
方法时必须调用该方法以释放资源。忽略关闭资源可能会对应用程序的性能产生负面影响。下一节中描述的try-
with-resources 语句将为您处理此步骤。
Catching Exceptions
使用文件 I/O 时,意外的情况就成为了现实:预期存在文件(或不存在),程序无法访问文件系统,默认文件系统实现不支持特定功能, 等等。可能会遇到许多错误。
所有访问文件系统的方法都可以抛出IOException
。最佳实践是通过将这些方法嵌入到 Java SE 7 发行版中引入的try-
with-resources 语句中来catch这些异常。 try-
with-resources 语句的优点在于,当不再需要时,编译器会自动生成代码以关闭资源。以下代码显示了外观:
Charset charset = Charset.forName("US-ASCII");
String s = ...;
try (BufferedWriter writer = Files.newBufferedWriter(file, charset)) {
writer.write(s, 0, s.length());
} catch (IOException x) {
System.err.format("IOException: %s%n", x);
}
有关更多信息,请参见try-with-resources 语句。
或者,您可以将文件 I/O 方法嵌入try
块中,然后在catch
块中catch任何异常。如果您的代码已打开任何流或通道,则应在finally
块中将其关闭。上面的示例使用 try-catch-finally 方法看起来类似于以下内容:
Charset charset = Charset.forName("US-ASCII");
String s = ...;
BufferedWriter writer = null;
try {
writer = Files.newBufferedWriter(file, charset);
writer.write(s, 0, s.length());
} catch (IOException x) {
System.err.format("IOException: %s%n", x);
} finally {
if (writer != null) writer.close();
}
有关更多信息,请参见catch和处理异常。
除IOException
外,许多特定的 exception 都扩展了FileSystemException。此类具有一些有用的方法,可以返回所涉及的文件(getFile),详细的消息字符串(getMessage),文件系统操作失败的原因(getReason)以及所涉及的“其他”文件(如果有的话(getOtherFile))。
以下代码段显示了如何使用getFile
方法:
try (...) {
...
} catch (NoSuchFileException x) {
System.err.format("%s does not exist\n", x.getFile());
}
为了清楚起见,本课中的文件 I/O 示例可能未显示异常处理,但是您的代码应始终包含异常处理。
Varargs
指定标志时,多个Files
方法接受任意数量的参数。例如,在以下方法签名中,CopyOption
参数后的省略号表示该方法接受可变数量的参数或* varargs *,通常称为它们:
Path Files.move(Path, Path, CopyOption...)
当方法接受 varargs 参数时,可以将其传递给逗号分隔的值列表或值数组(CopyOption[]
)。
在move
示例中,可以按以下方式调用该方法:
import static java.nio.file.StandardCopyOption.*;
Path source = ...;
Path target = ...;
Files.move(source,
target,
REPLACE_EXISTING,
ATOMIC_MOVE);
有关 varargs 语法的更多信息,请参见任意参数。
Atomic Operations
某些Files
方法(例如move
)可以在某些文件系统中自动执行某些操作。
“原子文件操作”是不能中断或“部分”执行的操作。要么执行整个操作,要么操作失败。当有多个进程在文件系统的同一区域上运行时,这一点很重要,并且需要确保每个进程都访问一个完整的文件。
Method Chaining
许多文件 I/O 方法都支持方法链接的概念。
您首先调用一个返回对象的方法。然后,您立即在那个对象上调用一个方法,该方法返回另一个对象,依此类推。许多 I/O 示例都使用以下技术:
String value = Charset.defaultCharset().decode(buf).toString();
UserPrincipal group =
file.getFileSystem().getUserPrincipalLookupService().
lookupPrincipalByName("me");
该技术可以生成紧凑的代码,并使您避免声明不需要的临时变量。
什么是地球仪?
Files
类中的两个方法都接受 glob 参数,但是* glob *是什么?
您可以使用 glob 语法指定 Pattern 匹配行为。
全局 Pattern 指定为字符串,并且与其他字符串(例如目录或文件名)匹配。 Glob 语法遵循几个简单规则:
-
星号
*
匹配任意数量的字符(包括所有字符)。 -
两个星号
**
的作用类似于*
,但跨越目录边界。此语法通常用于匹配完整路径。 -
问号
?
恰好匹配一个字符。 -
花括号指定子 Pattern 的集合。例如:
-
{sun,moon,stars}
匹配“太阳”,“月亮”或“星星”。{temp*,tmp*}
匹配所有以“ temp”或“ tmp”开头的字符串。
-
方括号表示一组单个字符,或者,如果使用连字符(
-
),则表示一系列字符。例如: -
[aeiou]
匹配任何小写的元音。-
[0-9]
匹配任何数字。 -
[A-Z]
匹配任何大写字母。 -
[a-z,A-Z]
匹配任何大写或小写字母。
-
在方括号中,*
,?
和\
相匹配。
-
所有其他字符都匹配。
-
要匹配
*
,?
或其他特殊字符,可以使用反斜杠字符\
对其进行转义。例如:\\
匹配单个反斜杠,而\?
匹配问号。
以下是 glob 语法的一些示例:
-
*.html
–匹配所有以* .html *结尾的字符串 -
???
–将所有字符串 完全匹配三个字母或数字 -
*[0-9]*
–匹配所有包含数字值的字符串 -
*.{htm,html,pdf}
–匹配以* .htm , .html 或 .pdf *结尾的任何字符串 -
a?*.java
–匹配以a
开头,至少一个字母或数字并以* .java *结尾的任何字符串 -
{foo*,*[0-9]*}
–匹配以* foo *开头的任何字符串 或包含数字值的任何字符串
Note:
如果要在键盘上键入全局 Pattern,并且其中包含特殊字符之一,则必须将 Pattern 放在引号("*"
)中,使用反斜杠(\*
),或者使用命令行支持的任何转义机制。
glob 语法功能强大且易于使用。但是,如果不足以满足您的需要,则也可以使用正则表达式。有关更多信息,请参见Regular Expressions类。
有关 glob sytnax 的更多信息,请参见FileSystem
类中getPathMatcher方法的 API 规范。
Link Awareness
Files
类具有“链接意识”。每个Files
方法要么检测遇到符号链接时的操作,要么提供一个选项,使您可以配置遇到符号链接时的行为。