File IO(NIO.2):读、写并创建文件

简介

本页讨论读,写,创建和打开文件的细节。有各种各样的文件I / O方法可供选择。为了帮助理解API,下图以复杂性排列文件I / O方法


在图的最左侧是实用程序方法readAllBytes,readAllLines和write方法,为简单的常见情况设计。右边是用于迭代流或文本行的方法,例如newBufferedReader,newBufferedWriter,然后是newInputStream和newOutputStream。这些方法可以与java.io包兼容。右边是处理ByteChannels,SeekableByteChannels和ByteBuffers的方法,比如newByteChannel方法。最后,对于需要文件锁定或内存映射I / O的高级应用程序,使用FileChannel的方法是最右边的。

注意:创建新文件的方法可以为文件指定一组可选的初始属性。例如,在支持POSIX标准集(如UNIX)的文件系统上,您可以在创建文件时指定文件所有者,组所有者或文件权限。“管理元数据”页面介绍文件属性,以及如何访问和设置它们

操作参数

本节中的几个方法使用可选的OpenOptions参数。此参数是可选的,API会告诉您,当没有指定时,该方法的默认行为是什么

支持以下StandardOpenOptions枚举:

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(Path, byte[], OpenOption...)
write(Path, Iterable< extends CharSequence>, Charset, OpenOption...)

以下代码片段显示了如何使用write方法:

Path file = ...;
byte[] buf = ...;
Files.write(file, buf);

对于Text文件的缓冲IO方法

java.nio.file包支持通道I / O,它可以将数据移入到一个缓冲区中,绕过一些IO的瓶颈

使用缓冲流读取文件:newBufferedReader(Path,Charset)方法打开一个文件进行读取,返回一个BufferedReader,可以用来以高效的方式从文件中读取文本。以下代码片段显示了如何使用newBufferedReader方法从文件中读取。该文件以“US-ASCII”编码。

Charset charset = Charset.forName("US-ASCII");
try (BufferedReader reader = Files.newBufferedReader(file, charset)) {
    String line = null;
    while ((line = reader.readLine()) != null) {
        System.out.println(line);
    }
} catch (IOException x) {
    System.err.format("IOException: %s%n", x);
}
使用缓冲流输出文件:您可以使用newBufferedWriter(Path,Charset,OpenOption ...)方法使用BufferedWriter写入文件。以下代码片段显示如何使用此方法创建以“US-ASCII”编码的文件:

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);
}

对于非缓冲流和互操作的java.io API

使用流读取一个文件:要打开文件进行阅读,可以使用newInputStream(Path,OpenOption ...)方法。该方法返回一个无缓冲的输入流,用于从文件读取字节。

Path file = ...;
try (InputStream in = Files.newInputStream(file);
    BufferedReader reader =
      new BufferedReader(new InputStreamReader(in))) {
    String line = null;
    while ((line = reader.readLine()) != null) {
        System.out.println(line);
    }
} catch (IOException x) {
    System.err.println(x);
}

使用IO流创建并输出一个文件:您可以使用newOutputStream(Path,OpenOption ...)方法创建文件,附加到文件或写入文件。此方法打开或创建用于写入字节的文件,并返回无缓冲的输出流。该方法采用可选的OpenOption参数。如果没有指定打开的选项,并且该文件不存在,将创建一个新的文件。如果文件存在,则会被截断。此选项相当于使用CREATE和TRUNCATE_EXISTING选项调用该方法。

以下示例打开日志文件。如果文件不存在,则创建它。如果文件存在,它将被打开以进行追加。

import static java.nio.file.StandardOpenOption.*;
import java.nio.file.*;
import java.io.*;

public class LogFileTest {

  public static void main(String[] args) {

    // Convert the string to a
    // byte array.
    String s = "Hello World! ";
    byte data[] = s.getBytes();
    Path p = Paths.get("./logfile.txt");

    try (OutputStream out = new BufferedOutputStream(
      Files.newOutputStream(p, CREATE, APPEND))) {
      out.write(data, 0, data.length);
    } catch (IOException x) {
      System.err.println(x);
    }
  }
}

用于通道和字节流的方法

使用通道流读写文件:当流I / O一次读取一个字符时,通道I / O一次读取一个缓冲区。 ByteChannel接口提供基本的读写功能。SeekableByteChannel是一个ByteChannel,它具有维持通道中位置并改变该位置的能力。 SeekableByteChannel还支持截断与通道关联的文件,并查询文件的大小。

移动到文件中的不同点,然后从该位置读取或写入到该位置的能力使得文件的随机访问成为可能

通道I / O读取和写入有两种方法:newByteChannel(Path, OpenOption...)  和 newByteChannel(Path, Set<? extends OpenOption>, FileAttribute<?>...)

注意:newByteChannel方法返回一个SeekableByteChannel的实例。使用默认文件系统,您可以将此可寻找字节通道转换为FileChannel,以提供对更高级功能的访问,从而将文件的一个区域直接映射到内存中,以便更快的访问,锁定文件的一个区域,以便其他进程无法访问该文件,或从绝对位置读取和写入字节,而不影响通道的当前位置。

两个newByteChannel方法都可以指定一个OpenOption选项列表。除了另外一个选项,还支持newOutputStream方法使用的相同的打开选项:READ是必需的,因为SeekableByteChannel支持读写。 

指定READ打开通道读取。指定WRITE或APPEND打开通道进行写入。如果没有指定这些选项,则打开通道进行读取。 以下代码片段读取文件并将其打印到标准输出:

// Defaults to READ
try (SeekableByteChannel sbc = Files.newByteChannel(file)) {
    ByteBuffer buf = ByteBuffer.allocate(10);

    // Read the bytes with the proper encoding for this platform.  If
    // you skip this step, you might see something that looks like
    // Chinese characters when you expect Latin-style characters.
    String encoding = System.getProperty("file.encoding");
    while (sbc.read(buf) > 0) {
        buf.rewind();
        System.out.print(Charset.forName(encoding).decode(buf));
        buf.flip();
    }
} catch (IOException x) {
    System.out.println("caught exception: " + x);
以下为UNIX和其他POSIX文件系统编写的示例创建具有特定文件权限集的日志文件。此代码创建日志文件或附加到日志文件(如果它已经存在)。创建日志文件,具有对组的所有者和只读权限的读/写权限。
import static java.nio.file.StandardOpenOption.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.file.*;
import java.nio.file.attribute.*;
import java.io.*;
import java.util.*;

public class LogFilePermissionsTest {

  public static void main(String[] args) {
  
    // Create the set of options for appending to the file.
    Set<OpenOption> options = new HashSet<OpenOption>();
    options.add(APPEND);
    options.add(CREATE);

    // Create the custom permissions attribute.
    Set<PosixFilePermission> perms =
      PosixFilePermissions.fromString("rw-r-----");
    FileAttribute<Set<PosixFilePermission>> attr =
      PosixFilePermissions.asFileAttribute(perms);

    // Convert the string to a ByteBuffer.
    String s = "Hello World! ";
    byte data[] = s.getBytes();
    ByteBuffer bb = ByteBuffer.wrap(data);
    
    Path file = Paths.get("./permissions.log");

    try (SeekableByteChannel sbc =
      Files.newByteChannel(file, options, attr)) {
      sbc.write(bb);
    } catch (IOException x) {
      System.out.println("Exception thrown: " + x);
    }
  }
}

用于创建一个常规或者临时文件的方法

创建文件:您可以使用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

原文地址:https://www.cnblogs.com/hhx626/p/8320403.html