系统学习 Java IO (十三)----字符读写 Reader/Writer 及其经常使用子类

目录:系统学习 Java IO---- 目录,概览html

Reader

Reader 类是 Java IO API 中全部 Reader 子类的基类。 Reader 相似于 InputStream ,除了它是基于字符而不是基于字节的。 换句话说, Reader 用于读取文本,而 InputStream 用于读取原始字节。java

Writer

Writer 类是 Java IO API 中全部 Writer 子类的基类。 Writer 就像一个 OutputStream ,除了它是基于字符而不是基于字节的。 换句话说,Writer 用于写入文本,而 OutputStream 用于写入原始字节。
Writer 一般链接到某些数据目标,如文件,字符数组,网络套接字等。数组

Unicode中的字符

许多应用程序使用 UTF(UTF-8或UTF-16)来存储文本数据。 可能须要一个或多个字节来表示 UTF-8 中的单个字符。 在 UTF-16 中,每一个字符须要 2 个字节来表示。 所以,在读取或写入文本数据时,数据中的单个字节可能与 UTF 中的一个字符不对应。 若是只是经过 InputStream 一次读取或写入 UTF-8 数据的一个字节,并尝试将每一个字节转换为字符,可能不会获得正确的文本。网络

Reader 类可以将字节解码为字符。 只须要告诉Reader 要解码的字符集。 这是在实例化 Reader 时执行的(当实例化其中一个子类时)。 一般会直接使用 Reader 子类而不是 Reader。Writer 同理。app

读取

部分方法以下:函数

方法 描述
void mark(int readAheadLimit) 标记流中的当前位置。
int read() 读取单个字符。
int read(char[] cbuf) 将字符读入数组。
abstract int read(char[] cbuf, int off, int len) 将字符读入数组的某一部分。
int read(CharBuffer target) 试图将字符读入指定的字符缓冲区。
boolean ready() 判断是否准备读取此流。

具体的使用须要参考对应的子类。学习

和 InputStream 相似,若是 read() 方法返回 -1 ,则 Reader 中没有更多数据要读取,而且能够关闭它。-1 做为 int 值,而不是 -1 做为 byte 或 char 值。编码

将字节流包装成字符流 InputStreamReader/OutputStreamWrite

InputStreamReade

InputStreamReade 类用于包装 InputStream ,从而将基于字节的输入流转换为基于字符的 Reader 。 换句话说,InputStreamReader 将 InputStream 的字节解释为文本而不是数字数据,是字节流通向字符流的桥梁。
为了达到最高效率,可要考虑在 BufferedReader 内包装 InputStreamReader。例如:线程

BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

一般用于从文件(或网络链接)中读取字符,其中字节表示文本。 例如,一个文本文件,其中字符编码为 UTF-8 。 可使用InputStreamReader 来包装 FileInputStream 以读取此类文件。
一个示例以下:code

InputStream inputStream = new FileInputStream("D:\\test\\1.txt");
Reader inputStreamReader = new InputStreamReader(inputStream);

int data = inputStreamReader.read();
while (data != -1) {
    char c = (char) data;
    System.out.print(c);
    data = inputStreamReader.read();
}
inputStreamReader.close();

首先建立一个 FileInputStream ,而后将其包装在 InputStreamReader 中。 其次,该示例经过 InputStreamReader 从文件中读取全部字符.
注意:为清楚起见,此处已跳过正确的异常处理。 要了解有关正确异常处理的更多信息,请转至目录的 Java IO 异常处理。

指定字符集

底层 InputStream 中的字符将使用某些字符编码进行编码。 此字符编码称为字符集,Charset。 两种经常使用字符集是 ASCII 和 UTF8(在某些状况下为UTF-16)。

默认字符集可能由于环境不一样而不一样,因此建议告诉 InputStreamReader 实例 InputStream 中的字符用什么字符集进行编码。 这能够在 InputStreamReader 构造函数中指定,能够只提供字符集的名字字符串,在底层会调用 Charset.forName("UTF-8") 进行转换的。 如下是设置 InputStreamReader 使用的字符集的示例:

InputStream inputStream = new FileInputStream("D:\\test\\1.txt");
Reader inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
关闭 InputStreamReader

一样建议使用 try with resources 来关闭流。一样,只要关闭最外层的包装流,里面的流会被系统自动关闭。

try(InputStreamReader inputStreamReader =
    new InputStreamReader(input)){
    int data = inputStreamReader.read();
    while(data != -) {
        System.out.print((char) data));
        data = inputStreamReader.read();
    } 
}

OutputStreamWriter

OutputStreamWriter 类用于包装 OutputStream ,从而将基于字节的输出流转换为基于字符的 Writer 。

若是须要将字符写入文件,OutputStreamWriter 很是有用,例如编码为 UTF-8 或 UTF-16。 而后能够将字符(char 值)写入 OutputStreamWriter ,它将正确编码它们并将编码的字节写入底层的 OutputStream 。
一个简单的示例以下:

OutputStream outputStream = new FileOutputStream("D:\\test\\1.txt");
Writer outputStreamWriter = new OutputStreamWriter(outputStream);
outputStreamWriter.write("Hello OutputStreamWriter");
outputStreamWriter.close();

注意:为清楚起见,此处已跳过正确的异常处理。 要了解有关正确异常处理的更多信息,请转至目录的 Java IO 异常处理。

同 InputStreamReader,OutputStreamWriter 也可使用指定的字符集输出,如:

Writer outputStreamWriter = new OutputStreamWriter(outputStream, "UTF-8");
关闭 OutputStreamReader

参考关闭 InputStreamReader 或 Java IO 异常处理。

读写文件 FileReader/FileWriter

FileReader

FileReader类使得能够将文件的内容做为字符流读取。 它的工做方式与 FileInputStream 很是类似,只是 FileInputStream 读取字节,而 FileReader 读取字符。 换句话说,FileReader 旨在读取文本。 取决于字符编码方案,一个字符能够对应于一个或多个字节。

FileReader 假定您要使用运行应用程序的计算机的默认字符编码来解码文件中的字节。 这可能并不老是你想要的,可是不能改变它!
若是要指定其余字符解码方案,请不要使用 FileReader 。 而是在 FileInputStream 上使用 InputStreamReader 。 InputStreamReader 容许您指定在读取基础文件中的字节时使用的字符编码方案。

FileWriter

FileWriter 类能够将字符写入文件。 在这方面它的工做原理与 FileOutputStream 很是类似,只是 FileOutputStream 是基于字节的,而 FileWriter 是基于字符的。 换句话说,FileWriter 用于写文本。 一个字符能够对应于一个或多个字节,这取决于使用的字符编码方案。
建立 FileWriter 时,能够决定是否要覆盖具备相同名称的任何现有文件,或者只是要追加内容到现有文件。 能够经过选择使用的 FileWriter 构造函数来决定。

  • FileWriter(File file, boolean append): 根据给定的 File 对象构造一个 FileWriter 对象。 示例以下:
Writer fileWriter = new FileWriter("c:\\data\\output.txt", true);  // 追加模式
Writer fileWriter = new FileWriter("c:\\data\\output.txt", false); // 默认状况,直接覆盖原文件

注意,只要成功 new 了一个 FileWriter 对象,没有指定是追加模式的话,那无论有没有调用 write() 方法,都会清空文件内容。

下面是一个读和写的例子:

public class FileRW {
    public static void main(String[] args) throws IOException {
        // 默认是覆盖模式
        File file = new File("D:\\test\\1.txt");
        Writer writer1 = new FileWriter(file);
        writer1.write("string from writer1, ");
        writer1.close();

        Writer writer2 = new FileWriter(file, true);
        writer2.write("append content from writer2");
        writer2.close();


        Reader reader = new FileReader(file);
        int data = reader.read();
        while (data != -1) {
            // 将会输出 string from writer1, append content from writer2
            System.out.print((char) data);
            data = reader.read();
        }
        reader.close();
    }
}

注意:为清楚起见,此处已跳过正确的异常处理。 要了解有关正确异常处理的更多信息,请转至Java IO异常处理。

其余行为和 InputStreamReader 差很少,就不展开讲了。

PipedReader/PipedWriter

读写管道 PipedReader 和 PipedWriter

PipedReader 类使得能够将管道的内容做为字符流读取。 所以它的工做方式与 PipedInputStream 很是类似,只是PipedInputStream 是基于字节的,而不是基于字符的。 换句话说,PipedReader 旨在读取文本。PipedWriter 同理。

构造器
方法 描述
PipedReader() 建立还没有链接的 PipedReader。
PipedReader(int pipeSize) 建立一个还没有链接的 PipedReader,并对管道缓冲区使用指定的管道大小。
PipedReader(PipedWriter src) 建立直接链接到传送 PipedWriter src 的 PipedReader。
PipedReader(PipedWriter src, int pipeSize) 建立一个 PipedReader,使其链接到管道 writer src,并对管道缓冲区使用指定的管道大小。
PipedWriter() 建立一个还没有链接到传送 reader 的传送 writer。
PipedWriter(PipedReader snk) 建立传送 writer,使其链接到指定的传送 reader。
读写以前,必须先创建链接

PipedReader 必须链接到 PipedWriter 才能够读 ,PipedWriter 也必须始终链接到 PipedReader 才能够写。就是说读写以前,必须先创建链接,有两种方式能够创建链接。

  1. 经过构造器建立,伪代码如 Piped piped1 = new Piped(piped2);
  2. 调用其中一个的 connect() 方法,伪代码如 Piped1.connect(Piped2);

而且一般,PipedReader 和 PipedWriter 由不一样的线程使用。 注意只有一个 PipedReader 能够链接到同一个 PipedWriter ,一个示例以下:

PipedWriter writer = new PipedWriter();
PipedReader reader = new PipedReader(writer);

writer.write("string form pipedwriter");
writer.close();

int data = reader.read();
while (data != -1) {
        System.out.print((char) data); // string form pipedwriter
        data = reader.read();
    }
reader.close();

注意:为清楚起见,这里忽略了正确的 IO 异常处理,而且没有使用不一样线程,不一样线程操做请参考 PipedInputStream 。

正如在上面的示例中所看到的,PipedReader 须要链接到 PipedWriter 。 当这两个字符流链接时,它们造成一个管道。 要了解有关 Java IO 管道的更多信息,请参考 管道流 PipedInputStream 部分。

读写字符数组 CharArrayReader/CharArrayWriter

ByteArrayInputStream/ByteArrayOutputStream 是对字节数组处理,CharArrayReader/CharArrayWriter 则是对字符数组进行处理,其用法是基本一致的,因此这里略微带过。

CharArrayReader

CharArrayReader 类能够将 char 数组的内容做为字符流读取。
只需将 char 数组包装在 CharArrayReader 中就能够很方便的生成一个 Reader 对象。

CharArrayWriter

CharArrayWriter 类能够经过 Writer 方法(CharArrayWriter是Writer的子类)编写字符,并将写入的字符转换为 char 数组。
在写入全部字符时,CharArrayWriter 上调用 toCharArray() 能很方便的生成一个字符数组。

两个类的构造函数:
方法 描述
CharArrayReader(char[] buf) 根据指定的 char 数组建立一个 CharArrayReader
CharArrayReader(char[] buf, int offset, int length) 根据指定的 char 数组建立一个 CharArrayReader
CharArrayWriter() 建立一个新的 CharArrayWriter ,默认缓冲区大小为 32
CharArrayWriter(int initialSize) 建立一个具备指定初始缓冲区大小的新 CharArrayWriter

注意:设置初始大小不会阻止 CharArrayWriter 存储比初始大小更多的字符。 若是写入的字符数超过了初始 char 数组的大小,则会建立一个新的更大的 char 数组,并将全部字符复制到新数组中。

一个使用实例以下:

CharArrayWriter writer = new CharArrayWriter();
writer.append('H');
writer.write("ello ".toCharArray());
writer.write("World");
char[] chars = writer.toCharArray();
writer.close();

CharArrayReader reader = new CharArrayReader(chars);
int data = reader.read();
while (data != -1) {
    System.out.print((char) data); // Hello World
    data = reader.read();
}
reader.close();

注意:为清楚起见,此处已跳过正确的异常处理。 要了解有关正确异常处理的更多信息,请转至 Java IO 异常处理。

相关文章
相关标签/搜索