# 文件操作

> 原文： [https://docs.oracle.com/javase/tutorial/essential/io/fileOps.html](https://docs.oracle.com/javase/tutorial/essential/io/fileOps.html)

[`Files`](https://docs.oracle.com/javase/8/docs/api/java/nio/file/Files.html) 类是`java.nio.file`包的另一个主要入口点。该类提供了一组丰富的静态方法，用于读取，写入和操作文件和目录。 `Files`方法适用于`Path`对象的实例。在继续讨论其余部分之前，您应该熟悉以下常见概念：

*   [发布系统资源](#resources)
*   [捕捉异常](#exception)
*   [Varargs](#varargs)
*   [原子作业](#atomic)
*   [方法链](#chaining)
*   [是什么？](#glob)
*   [链接意识](#linkaware)

此 API 中使用的许多资源（如流或通道）实现或扩展 [`java.io.Closeable`](https://docs.oracle.com/javase/8/docs/api/java/io/Closeable.html) 接口。 `Closeable`资源的要求是必须调用`close`方法以在不再需要时释放资源。忽略关闭资源可能会对应用程序的性能产生负面影响。 `try-` with-resources 语句（将在下一节中介绍）为您处理此步骤。

对于文件 I / O，意外情况是生活中的事实：文件存在（或不存在）预期时，程序无法访问文件系统，默认文件系统实现不支持特定功能， 等等。可能遇到许多错误。

访问文件系统的所有方法都可以抛出`IOException`。最佳实践是通过将这些方法嵌入 Java SE 7 发行版中引入的`try-` with-resources 语句来捕获这些异常。 `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 语句](../../essential/exceptions/tryResourceClose.html)。

或者，您可以将文件 I / O 方法嵌入`try`块中，然后捕获`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();
}

```

有关更多信息，请参阅[捕获和处理异常](../../essential/exceptions/handling.html)。

除`IOException`外，许多特定的例外都延伸 [`FileSystemException`](https://docs.oracle.com/javase/8/docs/api/java/nio/file/FileSystemException.html) 。这个类有一些有用的方法可以返回涉及的文件[（`getFile`）](https://docs.oracle.com/javase/8/docs/api/java/nio/file/FileSystemException.html#getFile--)，详细的消息字符串[（`getMessage`）](https://docs.oracle.com/javase/8/docs/api/java/nio/file/FileSystemException.html#getMessage--)，文件系统操作失败的原因 [（`getReason`）](https://docs.oracle.com/javase/8/docs/api/java/nio/file/FileSystemException.html#getReason--)和涉及的“其他”文件，如果有[（`getOtherFile`）](https://docs.oracle.com/javase/8/docs/api/java/nio/file/FileSystemException.html#getOtherFile--)。

以下代码段显示了如何使用`getFile`方法：

```
try (...) {
    ...    
} catch (NoSuchFileException x) {
    System.err.format("%s does not exist\n", x.getFile());
}

```

为清楚起见，本课程中的文件 I / O 示例可能不会显示异常处理，但您的代码应始终包含它。

指定标志时，有几个`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 语法的更多信息，请参阅[任意参数个数](../../java/javaOO/arguments.html#varargs)。

多个`Files`方法（如`move`）可以在某些文件系统中以原子方式执行某些操作。

_ 原子文件操作 _ 是不能被中断或“部分”执行的操作。执行整个操作或操作失败。当您在文件系统的同一区域上运行多个进程时，这很重要，并且您需要保证每个进程都访问一个完整的文件。

许多文件 I / O 方法支持 _ 方法链 _ 的概念。

您首先调用返回对象的方法。然后，您立即在 _ 上调用 _ 对象的方法，该对象返回另一个对象，依此类推。许多 I / O 示例使用以下技术：

```
String value = Charset.defaultCharset().decode(buf).toString();
UserPrincipal group =
    file.getFileSystem().getUserPrincipalLookupService().
         lookupPrincipalByName("me");

```

此技术生成紧凑的代码，使您可以避免声明不需要的临时变量。

`Files`类中的两个方法接受一个 glob 参数，但什么是 _glob_ ？

您可以使用 glob 语法指定模式匹配行为。

glob 模式被指定为字符串，并与其他字符串匹配，例如目录或文件名。 Glob 语法遵循几个简单的规则：

*   星号`*`匹配任意数量的字符（包括无）。
*   两个星号`**`的工作方式与`*`类似，但跨越目录边界。此语法通常用于匹配完整路径。
*   问号`?`恰好与一个字符匹配。
*   大括号指定子模式的集合。例如：
    *   `{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:** If you are typing the glob pattern at the keyboard and it contains one of the special characters, you must put the pattern in quotes (`"*"`), use the backslash (`\*`), or use whatever escape mechanism is supported at the command line.

* * *

glob 语法功能强大且易于使用。但是，如果它不足以满足您的需求，您还可以使用正则表达式。有关更多信息，请参阅[正则表达式](../../essential/regex/index.html)课程。

有关 glob 语法的更多信息，请参阅`FileSystem`类中 [`getPathMatcher`](https://docs.oracle.com/javase/8/docs/api/java/nio/file/FileSystem.html#getPathMatcher-java.lang.String-) 方法的 API 规范。

`Files`类是“链接感知”。每个`Files`方法都会检测到遇到符号链接时要执行的操作，或者它提供了一个选项，使您可以在遇到符号链接时配置行为。