返回介绍

10.5.1 输入流

发布于 2024-10-15 23:56:23 字数 2685 浏览 0 评论 0 收藏 0

当然,我们经常想做的一件事情是将格式化的输出打印到控制台,但那已在第 5 章创建的 com.bruceeckel.tools 中得到了简化。

第 1 到第 4 部分演示了输入流的创建与使用(尽管第 4 部分展示了将输出流作为一个测试工具的简单应用)。

1. 缓冲的输入文件

为打开一个文件以便输入,需要使用一个 FileInputStream,同时将一个 String 或 File 对象作为文件名使用。为提高速度,最好先对文件进行缓冲处理,从而获得用于一个 BufferedInputStream 的构建器的结果句柄。为了以格式化的形式读取输入数据,我们将那个结果句柄赋给用于一个 DataInputStream 的构建器。DataInputStream 是我们的最终(final)对象,并是我们进行读取操作的接口。

在这个例子中,只用到了 readLine() 方法,但理所当然任何 DataInputStream 方法都可以采用。一旦抵达文件末尾,readLine() 就会返回一个 null(空),以便中止并退出 while 循环。

“String s2”用于聚集完整的文件内容(包括必须添加的新行,因为 readLine() 去除了那些行)。随后,在本程序的后面部分中使用 s2。最后,我们调用 close(),用它关闭文件。从技术上说,会在运行 finalize() 时调用 close()。而且我们希望一旦程序退出,就发生这种情况(无论是否进行垃圾收集)。然而,Java 1.0 有一个非常突出的错误(Bug),造成这种情况不会发生。在 Java 1.1 中,必须明确调用 System.runFinalizersOnExit(true),用它保证会为系统中的每个对象调用 finalize()。然而,最安全的方法还是为文件明确调用 close()。

2. 从内存输入

这一部分采用已经包含了完整文件内容的 String s2,并用它创建一个 StringBufferInputStream(字串缓冲输入流)——作为构建器的参数,要求使用一个 String,而非一个 StringBuffer)。随后,我们用 read() 依次读取每个字符,并将其发送至控制台。注意 read() 将下一个字节返回为 int,所以必须将其造型为一个 char,以便正确地打印。

3. 格式化内存输入

StringBufferInputStream 的接口是有限的,所以通常需要将其封装到一个 DataInputStream 内,从而增强它的能力。然而,若选择用 readByte() 每次读出一个字符,那么所有值都是有效的,所以不可再用返回值来侦测何时结束输入。相反,可用 available() 方法判断有多少字符可用。下面这个例子展示了如何从文件中一次读出一个字符:

//: TestEOF.java
// Testing for the end of file while reading
// a byte at a time.
import java.io.*;

public class TestEOF {
  public static void main(String[] args) {
    try {
      DataInputStream in = 
        new DataInputStream(
         new BufferedInputStream(
          new FileInputStream("TestEof.java")));
      while(in.available() != 0)
        System.out.print((char)in.readByte());
    } catch (IOException e) {
      System.err.println("IOException");
    }
  }
} ///:~

注意取决于当前从什么媒体读入,avaiable() 的工作方式也是有所区别的。它在字面上意味着“可以不受阻塞读取的字节数量”。对一个文件来说,它意味着整个文件。但对一个不同种类的数据流来说,它却可能有不同的含义。因此在使用时应考虑周全。

为了在这样的情况下侦测输入的结束,也可以通过捕获一个违例来实现。然而,若真的用违例来控制数据流,却显得有些大材小用。

4. 行的编号与文件输出

这个例子展示了如何 LineNumberInputStream 来跟踪输入行的编号。在这里,不可简单地将所有构建器都组合起来,因为必须保持 LineNumberInputStream 的一个句柄(注意这并非一种继承环境,所以不能简单地将 in4 造型到一个 LineNumberInputStream)。因此,li 容纳了指向 LineNumberInputStream 的句柄,然后在它的基础上创建一个 DataInputStream,以便读入数据。

这个例子也展示了如何将格式化数据写入一个文件。首先创建了一个 FileOutputStream,用它同一个文件连接。考虑到效率方面的原因,它生成了一个 BufferedOutputStream。这几乎肯定是我们一般的做法,但却必须明确地这样做。随后为了进行格式化,它转换成一个 PrintStream。用这种方式创建的数据文件可作为一个原始的文本文件读取。

标志 DataInputStream 何时结束的一个方法是 readLine()。一旦没有更多的字串可以读取,它就会返回 null。每个行都会伴随自己的行号打印到文件里。该行号可通过 li 查询。

可看到用于 out1 的、一个明确指定的 close()。若程序准备掉转头来,并再次读取相同的文件,这种做法就显得相当有用。然而,该程序直到结束也没有检查文件 IODemo.txt。正如以前指出的那样,如果不为自己的所有输出文件调用 close(),就可能发现缓冲区不会得到刷新,造成它们不完整。。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文