在上一篇文章中介绍了字节流,这一篇用同样的形式介绍字符流。
字符流
字符流的处理单元为1个字符,只能处理文本数据,与字节流直接操作磁盘不同,字符流用到了缓冲区。对相应的API写测试方法的时候与字节流类似的就不写了,重点是各个类的用法。
至于为什么有了字节流还要字符流请看这篇文章。
字符输入流
Reader输入流:
字符输入流并没有像字节输入流那样完全符合装饰者模式或者说算是装饰者模式的变种,例如BufferedReader并没有继承FilterReader而是直接继承了Reader类。
- 抽象构件角色:Reader类;
- 具体构件角色:InputStreamReader及其子类;
- 装饰角色:FilterReader类;
- 具体装饰角色:BufferedReader及其子类,FilterReader子类。
Reader
Reader是所有字符输入流的父类。
//将字符读入指定缓冲区
public int read(java.nio.CharBuffer target) throws IOException;
//读取一个字符
public int read() throws IOException;
//读取一个字符数组
public int read(char cbuf[]) throws IOException;
//从字符数组下标为off开始读取len个字符
abstract public int read(char cbuf[], int off, int len) 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;
InputStreamReader
InputStreamReader是字节流InputStream到字符流Reader的桥梁。
构造函数:
//传入字节输入流,将此字节流按默认字符集转换为字符流
public InputStreamReader(InputStream in);
//传入字节输入流和字符集名称,将此字节流按指定字符集转换为字符流
public InputStreamReader(InputStream in, String charsetName)throws UnsupportedEncodingException;
//传入字节输入流和字符集,将此字节流按指定字符集转换为字符流
public InputStreamReader(InputStream in, Charset cs);
//传入字节流和字符集解码器,将此字节流使用指定字符集解码器转换为字符流
public InputStreamReader(InputStream in, CharsetDecoder dec);
特有方法:
//获取此输入流的字符编码名称
public String getEncoding();
测试程序及输出结果:
//测试程序
public static void main(String[] args) {
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream("D:\\FileInputStream\\hello.txt");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
InputStreamReader isr = new InputStreamReader(fileInputStream);
try {
char[] charArr = new char[1024];
int len = isr.read(charArr);
System.out.println(new String(charArr,0,len));
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
isr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//输出结果
锄禾日当午,汗滴禾下土。
谁知盘中餐,粒粒皆辛苦。
BufferedReader
BufferedReader类与BufferedInputStream作用类似,都是为输入流增加缓冲区的功能。
成员变量及构造函数:
//BufferedReader是一个装饰者类,因此会保留抽象构件角色的引用
private Reader in;
//字符数组,用作缓冲区
private char cb[];
//传入具体构件角色引用和缓冲区容量
public BufferedReader(Reader in, int sz);
//传入具体构件角色,缓冲区容量为默认值8192个字符
public BufferedReader(Reader in);
测试程序及输出结果:
//测试程序
public static void main(String[] args) {
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream("D:\\FileInputStream\\hello.txt");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
InputStreamReader isr = new InputStreamReader(fileInputStream);
BufferedReader bf = new BufferedReader(isr);
try {
char[] charArr = new char[1024];
int len = bf.read(charArr);
System.out.println(new String(charArr,0,len));
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
bf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//输出结果
锄禾日当午,汗滴禾下土。
谁知盘中餐,粒粒皆辛苦。
就像BufferedInputStream一样,目前是看不出来BufferedReader有什么作用的,在这篇文章中,我会仔细举例说明。
FileReader
FileReader继承于InputStreamReader,但构造函数与FileInputStream一样。
构造函数:
//传入文件路径,在这里可以看出来事实上还是new了一个FileInputStream对象,只是用父类构造转换成了字符流
public FileReader(String fileName) throws FileNotFoundException{
super(new FileInputStream(fileName));
}
//传入文件对象
public FileReader(File file) throws FileNotFoundException;
//传入文件描述符
public FileReader(FileDescriptor fd);
测试程序及输出结果:
//测试程序
public static void main(String[] args) {
FileReader fileReader = null;
try {
fileReader = new FileReader("D:\\FileInputStream\\hello.txt");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
char[] charArr = new char[1024];
try {
int len = fileReader.read(charArr);
System.out.println(new String(charArr,0,len));
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fileReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//输出结果
锄禾日当午,汗滴禾下土。
谁知盘中餐,粒粒皆辛苦。
CharArrayReader
CharArrayReader类似于字节输入流中的ByteArrayInputStreaml类,实现了一个字符缓冲区。
成员变量及构造函数:
//用来实现缓冲区的字符数组
protected char buf[];
//当前的缓冲位置
protected int pos;
//标记在缓冲区中的位置
protected int markedPos = 0;
//缓冲区结束的索引
protected int count;
//传入字符数组用作缓冲区
public CharArrayReader(char buf[]);
//传入字节数组用作缓冲区,数组下标offset为缓冲区当前位置
public CharArrayReader(char buf[], int offset, int length);
测试程序及输出结果:
//测试程序
public static void main(String[] args) {
char[] buf = {'锄','禾','日','当','午',',','汗','滴','禾','下','土','。', '\n','谁','知','盘','中','餐',',','粒','粒','皆','辛','苦','。'};
char[] charArr = new char[1024];
CharArrayReader charArrayReader = new CharArrayReader(buf);
try {
int len = charArrayReader.read(charArr);
System.out.println(new String(charArr,0,len));
} catch (IOException e) {
e.printStackTrace();
}
}
//输出结果
锄禾日当午,汗滴禾下土。
谁知盘中餐,粒粒皆辛苦。
PipedReader
管道流在这篇文章详细介绍。
字符输出流
Writer输出流:
Writer
Writer是所有字符输出流的基类。
成员变量:
//缓冲区
private char[] writeBuffer;
常用方法:
//写入一个字符到缓冲区中
public void write(int c) throws IOException;
//写入一个字符数组到缓冲区
public void write(char cbuf[]) throws IOException;
//将指定字符数组从off开始len个字符写入缓冲区
abstract public void write(char cbuf[], int off, int len) throws IOException;
//将字符串写入缓冲区
public void write(String str) throws IOException;
//将字符串从off开始len个字符写入缓冲区
public void write(String str, int off, int len) throws IOException;
//将指定字符序列附加到缓冲区
public Writer append(CharSequence csq) throws IOException;
//将指定字符序列从start到end的字符附加到缓冲区
public Writer append(CharSequence csq, int start, int end) throws IOException;
//将指定字符附加到缓冲区
public Writer append(char c) throws IOException;
//刷新流,在关闭流之前调用此方法可以强制将缓冲区中的内容写入到文件中
abstract public void flush() throws IOException;
///刷新并关闭流
abstract public void close() throws IOException;
OutputStreamWriter
OutputStreamWriter是字节输出流OutputStream到Writer的桥梁。
构造函数:
//创建一个使用命名字符集的OutputStreamWriter
public OutputStreamWriter(OutputStream out, String charsetName)throws UnsupportedEncodingException;
//创建一个使用默认字符编码的OutputStreamWriter
public OutputStreamWriter(OutputStream out);
//创建一个使用给定字符集的OutputStreamWriter
public OutputStreamWriter(OutputStream out, Charset cs);
//创建一个使用给定字符集编码器的OutputStreamWriter
public OutputStreamWriter(OutputStream out, CharsetEncoder enc);
特有方法:
//获取此输出流的字符编码名称
public String getEncoding();
测试程序及输出结果:
//测试程序
public static void main(String[] args) {
char[] buf = {'锄','禾','日','当','午',',','汗','滴','禾','下','土','。', '\n','谁','知','盘','中','餐',',','粒','粒','皆','辛','苦','。'};
FileOutputStream fos = null;
try {
fos = new FileOutputStream("D:\\FileInputStream\\hello.txt");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
OutputStreamWriter osw = new OutputStreamWriter(fos);
try {
osw.write(buf);
System.out.println("此字符输出流的字符编码为:"+osw.getEncoding());
osw.append("哈");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
osw.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//输出结果
锄禾日当午,汗滴禾下土。
谁知盘中餐,粒粒皆辛苦。哈
上边是写入文件的!!!
此字符输出流的字符编码为:UTF8
上面测试程序可以尝试把close()方法去掉,结果并没有写入到文件中。可以选择用flush()方法强制将缓冲区中的内容写入到文件中并且输出流没有关闭,也可以像上面调用close()方法先将缓冲区中的内容强制写入到缓冲区中再关闭流。
BufferedWriter
BufferedWriter是与BufferedOutputStream类似,提供缓冲区功能,是一个装饰者类。
成员变量及构造函数:
//具体构件角色引用
private Writer out;
//用作缓冲区的字符数组
private char cb[];
//行分隔符
private String lineSeparator;
//传入具体构件角色引用,缓冲区大小为默认值:8192
public BufferedWriter(Writer out);
//传入具体构件角色引用和缓冲区大小
public BufferedWriter(Writer out, int sz);
特有方法:
//写入行分隔符
public void newLine() throws IOException;
懒得写测试程序了O__O "…跟BufferedReader用法是类似的。
FileWriter
与FileReader构造函数类似O__O "…
PipedWriter
管道流在这篇文章统一介绍。
CharArrayWriter
提供了字符缓冲区的功能O__O "…
好的,字节流与字符流介绍的差不多了,我会把这部分可能会有的问题在这篇文章写清楚一些。