读取和写入小文件
选择正确的 I/O 方法
有许多文件 I/O 方法可供选择。为了帮助理解 API,下表显示了在 Files
类上可用的文件 I/O 方法及其用例。
读取 | 写入 | 注释 |
---|---|---|
readAllBytes() , readAllLines() |
write() |
专为简单、常见的用例而设计。 |
newBufferedReader() |
newBufferedWriter() |
遍历文本流或行。 |
newInputStream() |
newOutputStream() |
这些方法与 java.io 包互操作。 |
newByteChannel() , SeekableByteChannel , ByteBuffer |
||
FileChannel |
高级应用程序、文件锁定和内存映射 I/O。 |
注意:创建新文件的方法使您能够为文件指定一组可选的初始属性。例如,在支持 POSIX 标准集(如 UNIX)的文件系统上,您可以在创建文件时指定文件所有者、组所有者或文件权限。在 管理元数据 部分中解释了文件属性以及如何访问和设置它们。
OpenOptions 参数
本节中的几种方法都采用可选的 OpenOption
参数。此参数是可选的,API 会告诉您在未指定任何参数时该方法的默认行为。
几个 Files 方法在指定标志时接受任意数量的参数。当您在参数类型后面看到省略号表示法时,它表示该方法接受可变数量的参数,或称为varargs。当方法接受 varargs 参数时,您可以传递一个逗号分隔的值列表或一个值数组。
以下 StandardOpenOption
枚举受支持
WRITE
– 以写入访问权限打开文件。APPEND
– 将新数据追加到文件末尾。此选项与 WRITE 或 CREATE 选项一起使用。TRUNCATE_EXISTING
– 将文件截断为零字节。此选项与 WRITE 选项一起使用。CREATE_NEW
– 创建一个新文件,如果文件已存在则抛出异常。CREATE
– 如果文件存在则打开文件,如果不存在则创建新文件。DELETE_ON_CLOSE
– 在关闭流时删除文件。此选项对于临时文件很有用。SPARSE
– 提示新创建的文件将是稀疏的。此高级选项在某些文件系统(如 NTFS)上得到认可,在这些文件系统上,具有数据“间隙”的大文件可以以更有效的方式存储,其中这些空间隙不会占用磁盘空间。SYNC
– 使文件(内容和元数据)与底层存储设备同步。DSYNC
– 使文件内容与底层存储设备同步。
用于小文件的常用方法
从文件读取所有字节或行
如果您有一个较小的文件,并且您想一次性读取其所有内容,您可以使用 readAllBytes(Path)
或 readAllLines(Path, Charset)
方法。这些方法为您处理大部分工作,例如打开和关闭流,但不适用于处理大型文件。以下代码显示了如何使用 readAllBytes()
方法
Path file = ...;
byte[] fileArray;
fileArray = Files.readAllBytes(file);
将所有字节或行写入文件
您可以使用其中一个 write 方法将字节或行写入文件。
write(Path, byte[], OpenOption...)
write(Path, Iterable< extends CharSequence>, Charset, OpenOption...)
以下代码片段显示了如何使用 write()
方法。
Path file = ...;
byte[] buf = ...;
Files.write(file, buf);
用于创建常规文件和临时文件的方法
创建文件
您可以使用 createFile(Path, FileAttribute<?>)
方法创建一个具有初始属性集的空文件。例如,如果您在创建时希望文件具有一组特定的文件权限,请使用 createFile()
方法来执行此操作。如果您没有指定任何属性,则文件将使用默认属性创建。如果文件已存在,则 createFile()
会抛出异常。
在一次原子操作中,createFile()
方法检查文件是否存在,并使用指定的属性创建该文件,这使得该过程更安全,可以防止恶意代码。
以下代码片段使用默认属性创建一个文件
Path file = ...;
try {
// Create the empty file with default permissions, etc.
Files.createFile(file);
} catch (FileAlreadyExistsException x) {
System.err.format("file named %s" +
" already exists%n", file);
} catch (IOException x) {
// Some other sort of failure, such as permissions.
System.err.format("createFile error: %s%n", x);
}
POSIX 文件权限有一个示例,它使用 createFile(Path, FileAttribute<?>)
创建一个具有预设权限的文件。
您还可以使用 newOutputStream()
方法创建新文件,如 使用流 I/O 创建和写入文件 部分所述。如果您打开一个新的输出流并立即关闭它,则会创建一个空文件。
创建临时文件
您可以使用以下 createTempFile()
方法之一创建临时文件
createTempFile(Path, String, String, FileAttribute<?>)
createTempFile(String, String, FileAttribute<?>)
第一个方法允许代码为临时文件指定一个目录,第二个方法在默认的临时文件目录中创建一个新文件。两种方法都允许您为文件名指定一个后缀,第一个方法还允许您指定一个前缀。以下代码片段给出了第二个方法的示例
try {
Path tempFile = Files.createTempFile(null, ".myapp");
System.out.format("The temporary file" +
" has been created: %s%n", tempFile)
;
} catch (IOException x) {
System.err.format("IOException: %s%n", x);
}
运行此文件的結果将类似于以下内容
The temporary file has been created: /tmp/509668702974537184.myapp
临时文件名的具体格式是平台特定的。
随机访问文件
随机访问文件允许对文件的內容进行非顺序或随机访问。要随机访问文件,您需要打开文件,查找特定位置,然后从该文件读取或写入该文件。
此功能可以通过 SeekableByteChannel
接口实现。 SeekableByteChannel
接口扩展了通道 I/O,引入了当前位置的概念。方法允许您设置或查询位置,然后您可以从该位置读取数据或写入数据。该 API 由几个易于使用的方法组成
position()
– 返回通道的当前位置position(long)
– 设置通道的位置read(ByteBuffer)
– 从通道读取字节到缓冲区write(ByteBuffer)
– 将字节从缓冲区写入通道truncate(long)
– 截断与通道连接的文件(或其他实体)
使用通道 I/O 读取和写入文件显示 Path.newByteChannel()
方法返回 SeekableByteChannel
的实例。在默认文件系统上,您可以按原样使用该通道,或者可以将其强制转换为 FileChannel
,从而获得对更高级功能的访问权限,例如将文件区域直接映射到内存以实现更快的访问,锁定文件区域,或从绝对位置读取和写入字节而不影响通道的当前位置。
以下代码片段使用 newByteChannel()
方法之一打开一个文件以供读写。返回的 SeekableByteChannel
被强制转换为 FileChannel
。然后,从文件开头读取 12 个字节,并将字符串“I was here!”写入该位置。文件中的当前位置移动到末尾,并将开头处的 12 个字节追加。最后,追加字符串“I was here!”,并关闭文件上的通道。
String s = "I was here!\n";
byte data[] = s.getBytes();
ByteBuffer out = ByteBuffer.wrap(data);
ByteBuffer copy = ByteBuffer.allocate(12);
try (FileChannel fc = (FileChannel.open(file, READ, WRITE))) {
// Read the first 12
// bytes of the file.
int nread;
do {
nread = fc.read(copy);
} while (nread != -1 && copy.hasRemaining());
// Write "I was here!" at the beginning of the file.
fc.position(0);
while (out.hasRemaining())
fc.write(out);
out.rewind();
// Move to the end of the file. Copy the first 12 bytes to
// the end of the file. Then write "I was here!" again.
long length = fc.size();
fc.position(length-1);
copy.flip();
while (copy.hasRemaining())
fc.write(copy);
while (out.hasRemaining())
fc.write(out);
} catch (IOException x) {
System.out.println("I/O Exception: " + x);
}
上次更新: 2023 年 1 月 25 日