释放资源和捕获异常
释放系统资源
此 API 中使用的许多资源(例如流或通道)实现或扩展了 java.io.Closeable
接口。一个 Closeable
资源的要求是必须调用 close()
方法以在不再需要时释放资源。忽略关闭资源可能会对应用程序的性能产生负面影响。下一节中描述的try-with-resources语句将为您处理此步骤。
关闭资源
为了简单起见,前面的示例省略了两件事:异常处理和关闭读取器。
所有 I/O 操作在 Java I/O API 中抛出相同的默认异常:IOException
。根据您访问的资源类型,可能会抛出更多异常。例如,如果您的reader
从文件读取字符,您可能需要处理FileNotFoundException
。
在您的应用程序中关闭 I/O 资源是必须的。如果让资源未关闭,最终会导致您的应用程序崩溃。
从 Java SE 7 开始,可以使用try-with-resources语句关闭 I/O 资源。让我们使用此模式重写前面的代码。
Path path = Paths.get("file.txt");
try (BufferedReader reader = Files.newBufferedReader(path)) {
// do something with the reader
} catch (IOException e) {
// do something with the exception
}
在此示例中,reader
对象可以在try块中使用。当程序离开此块时,无论它是正常离开还是异常离开,都会为您调用reader
对象的close()
方法。
关闭多个资源
您可能会看到使用其构造函数创建的文件读取器和缓冲读取器。这些是在 Java SE 7 中引入 Files
工厂类之前使用的模式。在这种情况下,您将看到创建了几个中间 I/O 资源,这些资源必须以正确的顺序关闭。
在使用文件读取器创建的缓冲读取器的情况下,正确的模式如下所示。
File file = new File("file.txt");
try (FileReader fileReader = new FileReader(file);
BufferedReader bufferedReader = new BufferedReader(fileReader);) {
// do something with the bufferedReader or the fileReader
} catch (IOException e) {
// do something with the exception
}
捕获异常
在文件 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 语句。
或者,您可以将文件 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 {
try{
if (writer != null)
writer.close();
} catch (IOException x) {
System.err.format("IOException: %s%n", x);
}
}
有关更多信息,请参阅部分 捕获和处理异常。
除了IOException
之外,许多特定异常扩展了FileSystemException
。此类具有一些有用的方法,可以返回所涉及的文件(getFile()
)、详细的消息字符串(getMessage()
)、文件系统操作失败的原因(getReason()
)以及所涉及的“其他”文件(如果有)(getOtherFile()
)。
以下代码片段显示了如何使用getFile()
方法
try (...) {
...
} catch (NoSuchFileException x) {
System.err.format("%s does not exist\n", x.getFile());
}
为了清晰起见,本节中的文件 I/O 示例可能不会显示异常处理,但您的代码应始终包含它。
使用可变参数
几个 Files 方法在指定标志时接受任意数量的参数。例如,在以下方法签名中,CopyOption
参数后的省略号表示该方法接受可变数量的参数,或者通常称为可变参数
Path Files.move(Path, Path, CopyOption...)
当方法接受可变参数参数时,您可以传递逗号分隔的值列表或值数组(CopyOption[]
)。
在以下示例中,该方法可以按如下方式调用
Path source = ...;
Path target = ...;
Files.move(source,
target,
REPLACE_EXISTING,
ATOMIC_MOVE);
有关可变参数语法的更多信息,请参阅部分 任意数量的参数。
方法链
许多文件 I/O 方法支持方法链的概念。
您首先调用返回对象的方法。然后,您立即调用该对象上的方法,该方法又返回另一个对象,依此类推。许多 I/O 示例使用以下技术
String value = Charset.defaultCharset().decode(buf).toString();
UserPrincipal group =
file.getFileSystem()
.getUserPrincipalLookupService()
.lookupPrincipalByName("me");
此技术可以生成简洁的代码,并使您能够避免声明不需要的临时变量。
上次更新: 2023 年 1 月 25 日