Java 简明教程

Java - Files and I/O

java.io 包包含了你执行 Java 中的输入输出 (I/O) 所可能需要的几乎所有类。所有这些流都代表了一个输入源和一个输出目标。java.io 包中的流支持许多数据,比如基本类型、对象、本地化的字符等。

Stream

流可以被定义为一个数据序列。流有两种:

  1. InPutStream - InputStream 用于从一个源读取数据。

  2. OutPutStream - OutputStream 用于向一个目标写入数据。

streams

Java 提供了对文件和网络的强大而灵活的 I/O 相关支持,但本教程涵盖了与流和 I/O 相关的非常基本的功能。我们一个一个地看最常用的例子:

Byte Streams

Java 字节流用于执行 8 位字节的输入和输出。虽然有许多与字节流相关的类,但最常用的类是 FileInputStreamFileOutputStream。下面是一个利用这两个类将一个输入文件复制到一个输出文件的示例:

Example

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class CopyFile {

   public static void main(String args[]) throws IOException {
      FileInputStream in = null;
      FileOutputStream out = null;

      try {
         in = new FileInputStream("input.txt");
         out = new FileOutputStream("output.txt");

         int c;
         while ((c = in.read()) != -1) {
            out.write(c);
         }
      }finally {
         if (in != null) {
            in.close();
         }
         if (out != null) {
            out.close();
         }
      }
   }
}

现在,我们有一个文件 input.txt,其中包含以下内容:

This is test for copy file.

接下来,编译上述程序并执行它,这将导致创建一个内容与 input.txt 中相同的名为 output.txt 的文件。那么,我们将上述代码放入 CopyFile.java 文件中,并执行以下操作 −

$javac CopyFile.java
$java CopyFile

Character Streams

Java Byte 流用于执行 8 位字节的输入和输出,而 Java Character 流用于执行 16 位 Unicode 的输入和输出。虽然存在许多与字符流相关的类,但最常用的类是 FileReaderFileWriter。尽管 FileReader 在内部使用 FileInputStream,FileWriter 在内部使用 FileOutputStream,但这里的主要区别在于 FileReader 一次读取两个字节,而 FileWriter 一次写入两个字节。

我们可重写上述示例,它利用这两个类将输入文件(包含 unicode 字符)复制到输出文件中 −

Example

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class CopyFile {

   public static void main(String args[]) throws IOException {
      FileReader in = null;
      FileWriter out = null;

      try {
         in = new FileReader("input.txt");
         out = new FileWriter("output.txt");

         int c;
         while ((c = in.read()) != -1) {
            out.write(c);
         }
      }finally {
         if (in != null) {
            in.close();
         }
         if (out != null) {
            out.close();
         }
      }
   }
}

现在,我们有一个文件 input.txt,其中包含以下内容:

This is test for copy file.

接下来,编译上述程序并执行它,这将导致创建一个内容与 input.txt 中相同的名为 output.txt 的文件。那么,我们将上述代码放入 CopyFile.java 文件中,并执行以下操作 −

$javac CopyFile.java
$java CopyFile

Standard Streams

所有的编程语言都提供对标准 I/O 的支持,用户程序可从键盘获取输入,然后在计算机屏幕上生成输出。如果您知道 C 或 C++ 编程语言,那么您肯定知道三个标准设备 STDIN、STDOUT 和 STDERR。同样,Java 提供了以下三个标准流 −

  1. Standard Input − 用于向用户程序输入数据,通常会将键盘用作标准输入流,表示为 System.in

  2. Standard Output − 用于输出用户程序产生的数据,通常会将计算机屏幕用于标准输出流,表示为 System.out

  3. Standard Error − 用于输出用户程序产生的错误数据,通常会将计算机屏幕用于标准错误流,表示为 System.err

以下是一个简单的程序,它创建 InputStreamReader 以读取标准输入流,直到用户键入“q” −

Example

import java.io.InputStreamReader;
public class ReadConsole {
   public static void main(String args[]) throws IOException {
      InputStreamReader cin = null;

      try {
         cin = new InputStreamReader(System.in);
         System.out.println("Enter characters, 'q' to quit.");
         char c;
         do {
            c = (char) cin.read();
            System.out.print(c);
         } while(c != 'q');
      }finally {
         if (cin != null) {
            cin.close();
         }
      }
   }
}

我们将上述代码保存在 ReadConsole.java 文件中,并尝试编译并执行它,如下面的程序所示。此程序将继续读取并输出相同的字符,直到我们按“q”为止 −

$javac ReadConsole.java
$java ReadConsole
Enter characters, 'q' to quit.
1
1
e
e
q
q

Reading and Writing Files

如前文所述,流可定义为数据序列。InputStream 用于从源读取数据,而 OutputStream 用于将数据写入目标。

以下是对输入和输出流进行处理的类层次结构。

file io

两个重要的流是 FileInputStreamFileOutputStream,本教程将对它们进行讨论。

FileInputStream

此流用于从文件中读取数据。可以使用关键字 new 创建对象,并且有若干种构造函数可用。

以下构造函数将文件名作为字符串以创建输入流对象来读取文件 −

InputStream f = new FileInputStream("C:/java/hello");

以下构造函数获取文件对象以创建输入流对象来读取文件。我们首先使用 File() 方法创建一个文件对象,如下所示 −

File f = new File("C:/java/hello");
InputStream f = new FileInputStream(f);

一旦您掌握了 InputStream 对象,即可以使用一组辅助方法来读取流或对流执行其他操作。

Sr.No.

Method & Description

1

public void close() throws IOException{} 此方法关闭文件输出流。释放与文件关联的任何系统资源。引发 IOException。

2

protected void finalize()throws IOException {} 此方法清理与文件的连接。确保在这个文件输出流的引用消失时,调用该文件输出流的 close 方法。引发 IOException。

3

public int read(int r)throws IOException{} 此方法从 InputStream 读取指定的字节数据。返回 int。返回下一个字节数据,如果到达文件末尾则返回 -1。

4

public int read(byte[] r) throws IOException{} 此方法从输入流中读取 r.length 个字节到一个数组中。返回读取的总字节数。如果到达文件末尾,则返回 -1。

5

public int available() throws IOException{} 提供从此文件输入流读取的字节数。返回 int。

还有其他重要的输入流,有关更多详细信息,您可以参考以下链接:

FileOutputStream

FileOutputStream 用于创建文件并将数据写入其中。流将在写入之前创建文件(如果尚未存在)。

下面有两个可用于创建 FileOutputStream 对象的构造函数。

下面的构造函数以字符串形式获取一个文件名,用于创建一个输入流对象以写入文件:

OutputStream f = new FileOutputStream("C:/java/hello")

下面的构造函数获取一个文件对象,用于创建一个输出流对象以写入文件。首先,我们使用 File() 方法创建一个文件对象,如下所示:

File f = new File("C:/java/hello");
OutputStream f = new FileOutputStream(f);

get OutputStream 对象后,可以使用一系列帮助方法将数据写入流或对流执行其他操作。

Sr.No.

Method & Description

1

public void close() throws IOException{} 此方法关闭文件输出流。释放与文件关联的任何系统资源。引发 IOException。

2

protected void finalize()throws IOException {} 此方法清理与文件的连接。确保在这个文件输出流的引用消失时,调用该文件输出流的 close 方法。引发 IOException。

3

public void write(int w)throws IOException{} 在此方法中,将指定的字节写入输出流。

4

public void write(byte[] w) 从上述字节数组中写入 w.length 个字节到 OutputStream 中。

还有其他重要输出流可用,有关更多详细信息,可以参考以下链接 −

Example

以下是演示 InputStream 和 OutputStream 的示例 −

import java.io.OutputStream;

public class fileStreamTest {

   public static void main(String args[]) {

      try {
         byte bWrite [] = {11,21,3,40,5};
         OutputStream os = new FileOutputStream("test.txt");
         for(int x = 0; x < bWrite.length ; x++) {
            os.write( bWrite[x] );   // writes the bytes
         }
         os.close();

         InputStream is = new FileInputStream("test.txt");
         int size = is.available();

         for(int i = 0; i < size; i++) {
            System.out.print((char)is.read() + "  ");
         }
         is.close();
      } catch (IOException e) {
         System.out.print("Exception");
      }
   }
}

上述代码将创建文件 test.txt,并以二进制格式写入给定数字。stdout 屏幕上的输出也会相同。

File Navigation and I/O

还有其他几个类我们可以接触到以了解文件导航和 I/O 的基础知识。

Directories in Java

目录是一个可以包含其他文件和目录列表的文件。使用 File 对象创建目录,以列出目录中可用的文件。有关完整详细信息,请查看可以在文件对象上调用的所有方法的列表以及与目录相关的方法。

Creating Directories

有两个有用的 File 实用方法可用于创建目录 −

  1. mkdir( ) 方法创建一个目录,成功时返回 true,失败时返回 false。失败表示文件对象中指定的路径已存在,或者由于整个路径尚未存在而无法创建目录。

  2. mkdirs() 方法创建目录及其所有父目录。

以下示例创建 "/tmp/user/java/bin" 目录 −

Example

import java.io.File;

public class CreateDir {

   public static void main(String args[]) {
      String dirname = "/tmp/user/java/bin";
      File d = new File(dirname);

      // Create directory now.
      d.mkdirs();
   }
}

编译并执行上述代码以创建 "/tmp/user/java/bin"。

Note − Java 会自动按照惯例处理 UNIX 和 Windows 上的路径分隔符。如果你在 Java 的 Windows 版本上使用正斜杠 (/),路径仍然会正确解析。

Listing Directories

可以使用 File 对象提供的 list( ) 方法来列出目录中可用的所有文件和目录,如下所示 −

Example

import java.io.File;

public class ReadDir {

   public static void main(String[] args) {
      File file = null;
      String[] paths;

      try {
         // create new file object
         file = new File("/tmp");

         // array of files and directory
         paths = file.list();

         // for each name in the path array
         for(String path:paths) {
            // prints filename and directory name
            System.out.println(path);
         }
      } catch (Exception e) {
         // if any error occurs
         e.printStackTrace();
      }
   }
}

这将根据 /tmp 目录中可用的目录和文件生成以下结果 −

Output

test1.txt
test2.txt
ReadDir.java
ReadDir.class