《Java网络编程》第一章—阅读器和书写器

java网络编程

第一章 阅读器和书写器



前言

阅读器(Reader)和书写器(Writer)是用于处理字符数据的流


一、阅读器和书写器概述

对应于输入和输出流类的层次体系,java提供了一个完整镜像的API,用来处理字符而不是字节。在镜像中,有两个抽象超类定义了读/写字符的基本API。这就是阅读器和书写器(Reader&Writer)。
java.io.Reader类指定读取字符API。
java.io.Writer指定写字符的API。
与输入输出流相同,阅读器与书写器也有对应的过滤器,以提供额外的服务或接口。
Reader和Writer最重要的具体子类是InputStreamReader和OutputStreamWriter类。

阅读器和书写器原理:

InputStream包含一个底层输入流,可以读取原始字节,它根据指定的编码方式,将字节转换为Unicode字符。
OutputStreamWriter 从运行的程序中接收Unicode字符,然后使用指定的编码方式将字符转换为字节,再将字节写入底层输出流中。

其他原始阅读器和书写器类

除了上述两个类,java.io还提供了以下几个原始阅读器和书写器类,它们可以读取字符而不需要底层输入流。

FileReader
FileWriter
StringReader
StringWriter
CharArrayReader
CharArrayWriter

二、书写器

Writer类是一个抽象类与OutputStream类似,也不直接使用,而使用场景都是以子类多态的方式进行。它包含以下5个write()方法和flush()、close()方法

1.Writer类方法

代码如下(示例):

public void write(int c) throws IOException
public void write(char cbuf[]) throws IOException
abstract public void write(char cbuf[], int off, int len) throws IOException
public void write(String str) throws IOException
public void write(String str, int off, int len) throws IOException
abstract public void flush() throws IOException;
abstract public void close() throws IOException;

子类实现write()使用示例,例如写入Hello

char[] hello = {'H','e','l','l','o'};
w.write(hello,0,hello.length);
或者
w.write(hello);
for(int i = 0; i<hello.length;i++){
w.write(hello[i]);
w.write("Hello",0,7)
}

代码写入多少字节以及字符取决于w的编码方式。

2.OutputStreamWriter类

OutputStreamWriter是Writer最重要的具体子类。OutputStreamWriter会从java程序接收字符。根据指定的编码方式将字符转换为字节,并写入底层输出流。

构造函数代码如下(示例):

public OutputStreamWriter(OutputStream out, String charsetName) throws UnsupportedEncodingException

在JDK中包括一个Sun的native2ascii工具,文档中列出了所有合法的编码方式。
如果没有指定编码方式,则使用默认编码方式。
目前Mac,Linux上默认编码方式是UTF-8,而Windows系统的默认编码方式通常是GBK(对于中文环境)或UTF-8(对于其他语言环境或特定配置)。

三、阅读器

Reader类是一个抽象类与InputStream类似,也不直接使用,而使用场景都是以子类多态的方式进行。它包含以下3个read()方法和skip()、close()、ready()、mark()、reset()、markSupported()方法

1.Reader类方法

代码如下(示例):

abstract public int read(char cbuf[], int off, int len) throws IOException;
public int read() throws IOException
public int read(char cbuf[]) throws IOException
public long skip(long n) throws IOException
public boolean ready() throws IOException
public boolean markSupported() 
public void mark(int readAheadLimit) throws IOException
public void reset() throws IOException
abstract public void close() throws IOException;

与InputStream类似,read()方法将一个Unicode字符做为一个int返回,可以是0-65535之前的值。
read(char cbuf[])使用字符填入数组,并返回实际读取的字符数量,结束时返回-1。
read(char cbuf[], int off, int len)也是将长度为len的字符读入从off下标开始的数组中。
skip 跳过多少个字符。mark和resset允许阅读器重置到字符序列中做标记的位置。
markSupported告知阅读器是否支持标记和重置。
额外的是阅读器有一个ready方法,返回一个boolean,表示阅读器是否还可以无阻塞读取。有一个问题是,有些字符编码方式对于不同字符会使用不同数量的字节。因此在实际从缓冲器区读取之前,很难说有多少个字符正在网络或文件系统的缓冲区等待。

2.InputStreamWriter类

InputStreamWriter是Writer最重要的具体子类。InputStreamWriter会从底层输入流(例如FileInputStream或TelnetInputStream)中读取字节。根据指定的编码方式将字节转换为字符,并返回字符。

构造函数代码如下(示例):

public InputStreamWriter(InputStream out, String charsetName) throws UnsupportedEncodingException

如果没有指定编码方式,则使用默认编码方式。

使用示例
以InputStreamReader 使用MacCyrillic编码方式将其转换为Unicode字符串:

public static String readerFunc(InputStream in) throws IOException{
        InputStreamReader r = new InputStreamReader(in, "MacCyrillic");
        StringBuilder sb =new StringBuilder();
        int c;
        while((c= r.read()) != -1) sb.append((char) c);
        return sb.toString();
    }

小知识

MacCyrillic是一种字符编码方案,它主要用于表示西里尔字母(Cyrillic alphabet)的字符。西里尔字母是斯拉夫语族(如俄语、乌克兰语、白俄罗斯语等)所使用的字母表。
Unicode,也被称为统一码、万国码或单一码,是一个字符编码标准。它旨在为世界上所有语言的字符提供一个统一的编码方案,使得不同语言的字符能够在同一个系统中同时使用。
UTF-8(Unicode Transformation Format - 8-bit)是Unicode字符集的一种编码方式,它使用1到4个字节的可变长度来表示一个Unicode字符。

四、过滤器阅读器和书写器

InputStreamReader和OutputStreamWriter类相当于输入和输出流之上的装饰器,把面向字节的接口替换为面向字符的接口。与过滤器流一样,过滤阅读器和书写器也有很多子类可以完成特定的过滤工作:
BufferedReader
BufferedWriter
LineNumberReader
PushbackReader
PrintWrite

他们都是基于字符的。缓冲类也具有一个内部字符数组作为缓冲区。
下面修改上述代码使用BufferedReader提高效率。

public static String readerFunc(InputStream in) throws IOException{
        Reader r = new InputStreamReader(in, "MacCyrillic");
        r = new BufferedReader(r,2048);
        StringBuilder sb =new StringBuilder();
        int c;
        while((c= r.read()) != -1) sb.append((char) c);
        return sb.toString();
    }

read每次只读一个字符效率太低,而加上过滤器阅读器只需要一行代码,其他代码不用大改,则会使得代码运行更快。
BufferedReader类拥有一个readLine()方法,可以读取一行文本,并返回一个字符串。


总结

输入输出流(InputStream/OutputStream):以字节(byte)为单位进行数据的输入输出操作,适用于处理二进制数据。
阅读器和书写器(Reader/Writer):以字符(char)为单位进行数据的输入输出操作,适用于处理文本数据。
输入输出流:不关心数据的编码方式,因为它们操作的是字节流。
阅读器和书写器:需要指定字符集(如UTF-8、GBK等),因为它们操作的是字符流,涉及到字符编码和解码的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZZZ_Tong

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值