Java Reader类

时间:2020-01-09 10:36:06  来源:igfitidea点击:

Java Reader类java.io.Reader是Java IO API中所有Reader类的基类。 JavaReader类似于Java InputStream,不同之处在于它是基于字符而不是基于字节的。换句话说,Java的"阅读器"用于读取文本(字符),而" InputStream"则用于读取原始字节。

Reader和来源

"Reader"通常连接到某些数据源,例如文件,字符数组,网络套接字等。这在Java IO概述文本中也有更详细的说明。

Unicode中的字符

如今,许多应用程序都使用Unicode(UTF-8或者UTF-16)存储文本数据。在UTF-8中,可能需要一个或者多个字节来表示单个字符。在UTF-16中,每个字符用2个字节表示。因此,在读取文本数据时,数据中的单个字节可能不对应于UTF中的一个字符。如果我们只是一次通过InputStream读取UTF-8数据中的一个字节,然后尝试将每个字节转换为char类型,则可能无法获得预期的文本。

为了解决这个问题,我们有Reader类。 " Reader"类能够将字节解码为字符。我们需要告诉"阅读器"要解码的字符集。当我们实例化Reader时(实际上,当我们实例化其子类之一时)便完成了此操作。

Java Reader子类

通常,我们将直接使用Reader子类,而不是直接使用Reader。 Java IO包含许多Reader子类。以下是JavaReader子类的列表:

  • InputStreamReader
  • CharArrayReader
  • 文件阅读器
  • PipedReader
  • BufferedReader
  • FilterReader
  • PushbackReader
  • LineNumberReader
  • 字符串阅读器

这是一个创建JavaFileReader的示例,它是JavaReader的子类:

Reader reader = new FileReader("/path/to/file/thefile.txt");

从Reader中读取字符

JavaReaderread()方法返回一个整数,该整数包含下一个读取的字符的char值。如果read()方法返回-1,则Reader中没有更多的数据可读取,因此可以将其关闭。也就是说,-1作为int值,而不是-1作为byte或者char值。这里有区别!

这是一个从JavaReader读取所有字符的示例:

Reader reader = new FileReader("/path/to/file/thefile.txt");

int theCharNum = reader.read();
while(theCharNum != -1) {
    char theChar = (char) theCharNum;

    System.out.print(theChar);

    theCharNum = reader.read();
}

注意,该代码示例如何首先从JavaReader中读取单个字符,并检查char数值是否等于-1. 如果没有,它将处理该char并继续读取,直到从Reader read()方法返回-1为止。

从Reader读取字符数组

JavaReader类还具有一个read()方法,该方法采用一个char数组作为参数,以及一个起始偏移量和长度。 char数组是read()方法将字符读入的数组。 offset参数是在char数组中的read()方法应该开始读入的位置。 length参数是read()方法应从偏移量开始并向前读取到char数组中的字符数。这是一个使用JavaReader将字符数组读入char数组的示例:

Reader reader = new FileReader("/path/to/file/thefile.txt");

char[] theChars = new char[128];

int charsRead = reader.read(theChars, 0, theChars.length);
while(charsRead != -1) {
    System.out.println(new String(theChars, 0, charsRead));
    charsRead = reader.read(theChars, 0, theChars.length);
}

" read(char [],offset,length)"方法返回读取到" char"数组中的字符数,如果没有更多的字符要在" Reader"中读取,则返回-1,例如,如果已达到"阅读器"所连接的文件。

Reader的性能

一次读取一个字符数组比一次从JavaReader读取单个字符要快。通过读取字符数组而不是一次读取单个字符,该差异很容易成为性能提高的10倍或者更多。

所获得的确切速度取决于读取的char数组的大小以及运行代码的计算机的OS,硬件等。在决定之前,我们应该研究目标系统的硬盘缓冲区大小等。但是,如果缓冲区大小为8KB或者更高,则可以实现很好的加速。但是,一旦char数组超出了底层操作系统和硬件的容量,我们将不会从更大的char数组中获得更大的加速。

我们可能必须尝试不同的字节数组大小并测量读取性能,以找到最佳的" char"数组大小。

通过BufferedReader进行透明缓冲

我们可以使用Java BufferedReader从Reader中添加透明的,自动的读取和缓冲字节数组的函数。 BufferedReader从底层的Reader读取一大堆charchar数组中。然后,我们可以从" BufferedReader"中逐个读取字节,并且仍然可以从读取" chars"数组而不是一次读取一个字符中获得很大的提速。这是将JavaReader包装在BufferedReader中的示例:

Reader input = new BufferedReader(
                      new FileReader("c:\data\input-file.txt"),
                        1024 * 1024        /* buffer size */
    );

注意," BufferedReader"是" Reader"的子类,可以在任何可以使用" Reader"的地方使用。

跳过字符

JavaReader类具有一个名为skip()的方法,该方法可用于跳过我们不想读取的输入中的许多字符。我们将要跳过的字符数作为参数传递给skip()方法。这是一个从JavaReader跳过字符的示例:

long charsSkipped = reader.skip(24);

这个例子告诉JavaReader跳过Reader中接下来的24个字符。 skip()方法返回被跳过的实际字符数。在大多数情况下,该数字与我们请求的跳过数字相同,但是如果"阅读器"中剩余的字符少于我们请求跳过的数字,则返回的跳过字符数可以小于我们请求的字符数跳过了。

关闭Reader

当我们从"阅读器"中读取完字符后,我们应该记得将其关闭。关闭阅读器是通过调用其close()方法完成的。这是关闭Reader的样子:

reader.close();

我们还可以使用Java 7中引入的Java try with resources构造。这是如何通过try-with-resources构造使用和关闭" InputStreamReader"外观的方法:

try(Reader reader = new FileReader("/path/to/file/thefile.txt")){

    int data = reader.read();
    while(data != -) {
        System.out.print((char) data));
        data = reader.read();
    }

}

请注意,不再有任何显式的close()方法调用。 try-with-resources构造可以解决这一问题。