https://docs.oracle.com/javase/tutorial/essential/io/fileOps.html
文件操作
的 Files
类是另一主要入口点java.nio.file
包。这个类提供了一套丰富的静态方法来读取,写入和操作文件和目录。这些Files
方法用于Path
对象的实例。在继续阅读其余部分之前,您应该熟悉以下常见概念:
释放系统资源
在这个API中使用的许多资源,例如流或通道,实现或扩展java.io.Closeable
接口。可Closeable
资源的要求是必须调用close
以在不再需要时释放资源。忽略关闭资源可能会对应用程序的性能产生负面影响。下一节中描述的try-
with-resources语句为您处理这一步骤。
捕捉异常
对于文件I / O,意外情况是一个事实:文件存在(或不存在),预期,程序无权访问文件系统,默认文件系统实现不支持特定功能, 等等。可能会遇到许多错误。
所有访问文件系统的方法都会抛出一个IOException
。通过将这些方法嵌入try-
Java SE 7发行版中引入的with-resources语句来捕获这些异常是最佳实践。在try-
与资源语句,编译器会自动生成的代码,关闭时不再需要的资源(S)的优势。以下代码显示了这可能看起来如何:
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); }
有关更多信息,请参阅 “试用资源声明”。
或者,您可以将文件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(); }
有关更多信息,请参阅 捕获和处理例外。
除此之外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...)
当一个方法接受varargs参数时,可以将它传递给一个逗号分隔的值列表或值(数组CopyOption[]
)。
在这个move
例子中,该方法可以被调用,如下所示:
import static java.nio.file.StandardCopyOption.*; Path source = ...; Path target = ...; Files.move(source, target, REPLACE_EXISTING, ATOMIC_MOVE);
有关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开头的任何字符串或包含数值的任何字符串
注意: 如果要在键盘上键入glob模式并且它包含某个特殊字符,则必须将该模式置于引号(
"*"
)中,使用反斜线(
\*
)或使用命令行支持的任何转义机制。
glob语法功能强大且易于使用。但是,如果它不足以满足您的需求,您还可以使用正则表达式。有关更多信息,请参阅 正则表达式课程。
有关glob sytnax的更多信息,请参阅类中getPathMatcher
方法的API规范 FileSystem
。
链接意识
该Files
课程是“链接感知”。每个Files
方法都会检测遇到符号链接时要执行的操作,或者提供一个选项,以便您在遇到符号链接时配置行为。