系列中的上一篇
当前教程
读取和写入小文件
系列中的下一篇

系列中的上一篇: 释放资源和捕获异常

系列中的下一篇: 读取和写入文本文件

读取和写入小文件

 

选择正确的 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 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() 方法之一创建临时文件

第一个方法允许代码为临时文件指定一个目录,第二个方法在默认的临时文件目录中创建一个新文件。两种方法都允许您为文件名指定一个后缀,第一个方法还允许您指定一个前缀。以下代码片段给出了第二个方法的示例

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 由几个易于使用的方法组成

使用通道 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 日


系列中的上一篇
当前教程
读取和写入小文件
系列中的下一篇

系列中的上一篇: 释放资源和捕获异常

系列中的下一篇: 读取和写入文本文件