Java_io体系之CharArrayReader、CharArrayWriter简介、走进源码及示例——13
一:CharArrayReader
1、类功能简介:
字符数组输入流car 、与ByteArrayInputStream相同、用于将自带的内置缓存字符数组中的字符读取到程序中。与ByteArrayInputStream不同的是:当调用car的close方法是将内置缓存数组cbuffer设为null、而且car会抛出IOException异常(ensureOpen方法、即当cbuffer为null时则认为car关闭)。方法与使用功能与bais很相似、说白了区别就在于一个是从内置字节数组中读取字节、一个是从内置字符数组中读取字符。有一点是与bais不同的地方、就是他们的父类的区别、Reader比InputStream多实现一个Readable接口、这个接口要求提供一个方法、是将字符数组读取到指定的缓存数组中、其实完全可以用read(char[] cbuf, int off, int len)来代替实现。。。
2、CharArrayReader API简介:
A:关键字
protected char buf[]; 自带字符数组
protected int pos; buf中下一个要被读取的字符位置
protected int markedPos = 0; buf中被mark的字符下标
protected int count; 字符数组中总数、buf中索引为count和下一个都没有字符存在。
B:构造方法
CharArrayReader(char buf[]); 使用传入的buf构造CharArrayReader
CharArrayReader(char buf[], int offset, int length); 使用传入的buf的一部分构造CharArrayReader
C:一般方法
void close(); 关闭此流、
void mark(int readAheadLimit); 标记当前流读取的位置
void markSupport(); 检测此流是否支持标记
int read(); 读取一个字符、并以整数形式返回
int read(char[] c, int off, int len); 将buf中len个字符读取到下标从off开始的b中、返回读取的字符个数
boolean ready(); 查看CharArrayReader是否可读。
void reset(); 将此流开始位置重置到最后一次调用mark是流的读取位置
long skip(long n); 丢弃buf中n个字符、返回实际丢弃的字符个数
3、源码分析
package com.chy.io.original.code;
import java.io.IOException;
/**
* 字符数组输入流
*/
public class CharArrayReader extends Reader {
/** 自带字符数组 */
protected char buf[];
/** buf中下一个要被读取的字符位置 */
protected int pos;
/** buf中被mark的字符下标 */
protected int markedPos = 0;
/**
* 字符数组中总数、buf中索引为count和下一个都没有字符存在。
*/
protected int count;
/**
* 使用传入的buf构造CharArrayReader、并初始化CharArrayReader的buf、以及buf中将要被读取的字符的下标及总数。
*/
public CharArrayReader(char buf[]) {
this.buf = buf;
this.pos = 0;
this.count = buf.length;
}
/**
* 使用传入的buf构造CharArrayReader、并初始化CharArrayReader的buf、以及buf中将要被读取的字符的下标及总数。
*/
public CharArrayReader(char buf[], int offset, int length) {
if ((offset < 0) || (offset > buf.length) || (length < 0) ||
((offset + length) < 0)) {
throw new IllegalArgumentException();
}
this.buf = buf;
this.pos = offset;
this.count = Math.min(offset + length, buf.length);
this.markedPos = offset;
}
/** 检测此流是否关闭、看此流的close()方法就能明白这个方法*/
private void ensureOpen() throws IOException {
if (buf == null)
throw new IOException("Stream closed");
}
/**
* 读取单个字符
*/
public int read() throws IOException {
synchronized (lock) {
ensureOpen();
if (pos >= count)
return -1;
else
return buf[pos++];
}
}
/**
* 将buf中len个字符读取到下标从off开始的b中、返回读取的字符个数。
*/
public int read(char b[], int off, int len) throws IOException {
synchronized (lock) {
ensureOpen();
if ((off < 0) || (off > b.length) || (len < 0) ||
((off + len) > b.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return 0;
}
//buf中没有字符
if (pos >= count) {
return -1;
}
//buf中字符不够len个
if (pos + len > count) {
len = count - pos;
}
//传入的len<=0、返回0
if (len <= 0) {
return 0;
}
System.arraycopy(buf, pos, b, off, len);
pos += len;
return len;
}
}
/**
* 丢弃buf中n个字符、返回实际丢弃的字符个数。
*/
public long skip(long n) throws IOException {
synchronized (lock) {
ensureOpen();
//如果buf中剩余字符不够n个、丢弃buf中现有所有字符
if (pos + n > count) {
n = count - pos;
}
//传入的n为负、不丢弃。
if (n < 0) {
return 0;
}
pos += n;
return n;
}
}
/**
* 查看CharArrayReader是否可读。判断条件是buf中是否还有字符存在。
*/
public boolean ready() throws IOException {
synchronized (lock) {
ensureOpen();
return (count - pos) > 0;
}
}
/**
* 是否支持mark?是
*/
public boolean markSupported() {
return true;
}
/**
* 标记当前buf中下一个将要被读取的字符下标。
* 传入的readAheadLimit同ByteArrayInputStream一样、无效。
*/
public void mark(int readAheadLimit) throws IOException {
synchronized (lock) {
ensureOpen();
markedPos = pos;
}
}
/**
* 将此流开始位置重置到最后一次调用mark是流的读取位置。
*/
public void reset() throws IOException {
synchronized (lock) {
ensureOpen();
pos = markedPos;
}
}
/**
* 关闭、清空buf。
*/
public void close() {
buf = null;
}
}
4、实例演示:
二:CharArrayWriter
1、类功能简介:
字符数组输出流caw、用于将字符写入到内置字符缓存数组char[] buf中、当此数组存放满员时会自动扩容、同样与ByteArrayOutputStream相比他也提供了几个操作buf中字符的方法、可使用 toCharArray() 和 toString() 获取数据、还可使用writeTo(Writer out)将buf写入到底层流中。同样在此类上调用 close()、flush()无效,不会产生IOException、并且在关闭该流后仍然可以调用此类中的各个方法。
2、CharArrayWriter API简介:
A:关键字
protected char buf[]; 用于存放写入CharArrayWriter的字符、存满自动扩容。
protected int count; buf中现有的字符数
B:构造方法
public CharArrayWriter() 使用默认buf大小创建CharArrayWriter。
public CharArrayWriter(int initialSize) 使用指定的buf大小创建CharArrayWriter。
C:一般方法
CharArrayWriter append(CharSequence csq) 将一串有序字符序列写入buf中
CharArrayWriter append(CharSequence csq, int start, int end) 将一串有序字符序列的一部分写入buf中
CharArrayWriter append(char c) 将一个字符写入buf中
void close() 关闭此流(没有效果)
void flush() flush此流(没有效果)
void reset() 清空buf、重头开始
int size() 查看当前buf中字符总数
char[] toCharArray() 将buf中内容转换成char[]
String toString() 将buf中字符转换成String返回
void write(int c) 写入一个字符。
void write(char c[], int off, int len) 将一个char[]的一部分写入buf中、若buf满、扩容。
void write(String str, int off, int len) 将一个字符串写入buf中、满自动扩容
void writeTo(Writer out) 将buf中现有的字节写入到subWriter(out)中
3、源码分析
package com.chy.io.original.code;
import java.io.IOException;
import java.util.Arrays;
/**
* Writer的一个子类、可将字符写入到自带的一个缓存字符数组buf中、
* 当buf写满时、会自动扩容。
*/
public class CharArrayWriter extends Writer {
/**
* 用于存放写入CharArrayWriter的字符、存满自动扩容。
*/
protected char buf[];
/**
* buf中现有的字符数
*/
protected int count;
/**
* 使用默认buf大小创建CharArrayWriter。
*/
public CharArrayWriter() {
this(32);
}
/**
* 使用指定的buf大小创建CharArrayWriter。
*/
public CharArrayWriter(int initialSize) {
if (initialSize < 0) {
throw new IllegalArgumentException("Negative initial size: "
+ initialSize);
}
buf = new char[initialSize];
}
/**
* 写入一个字符。
*/
public void write(int c) {
synchronized (lock) {
int newcount = count + 1;
//如果buf存满、则将buf容量扩大1倍、并将原来buf中count字符copy到新的buf中
if (newcount > buf.length) {
buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newcount));
}
//将新写入的字符存入到buf第count个下标位置。
buf[count] = (char)c;
count = newcount;
}
}
/**
* 将一个char[]的一部分写入buf中、若buf满、扩容。
*/
public void write(char c[], int off, int len) {
if ((off < 0) || (off > c.length) || (len < 0) ||
((off + len) > c.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return;
}
synchronized (lock) {
int newcount = count + len;
if (newcount > buf.length) {
buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newcount));
}
System.arraycopy(c, off, buf, count, len);
count = newcount;
}
}
/**
* 将一个字符串写入buf中、满自动扩容
*/
public void write(String str, int off, int len) {
synchronized (lock) {
int newcount = count + len;
if (newcount > buf.length) {
buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newcount));
}
str.getChars(off, off + len, buf, count);
count = newcount;
}
}
/**
* 将buf中现有的字节写入到subWriter(out)中
*/
public void writeTo(Writer out) throws IOException {
synchronized (lock) {
out.write(buf, 0, count);
}
}
/**
* 将一串有序字符序列写入buf中
*/
public CharArrayWriter append(CharSequence csq) {
String s = (csq == null ? "null" : csq.toString());
write(s, 0, s.length());
return this;
}
/**
* 将一串有序字符序列的一部分写入buf中
*/
public CharArrayWriter append(CharSequence csq, int start, int end) {
String s = (csq == null ? "null" : csq).subSequence(start, end).toString();
write(s, 0, s.length());
return this;
}
/**
* 将一个字符写入buf中
*/
public CharArrayWriter append(char c) {
write(c);
return this;
}
/**
* 清空buf、重头开始
*/
public void reset() {
count = 0;
}
/**
* 将buf中内容转换成char[]
*/
public char toCharArray()[] {
synchronized (lock) {
return Arrays.copyOf(buf, count);
}
}
/**
* 查看当前buf中字符总数
*/
public int size() {
return count;
}
/**
* 将buf中字符转换成String返回
*/
public String toString() {
synchronized (lock) {
return new String(buf, 0, count);
}
}
/**
* flush CharArrayWriter、因此方法对CharArrayWriter没有效果、所以方法体是空!
*/
public void flush() { }
/**
* 同样、关闭CharArrayWriter没有用、调用close()关闭此流、此流的方法一样能用。
*/
public void close() { }
}
4、实例演示:
package com.chy.io.original.test;
import java.io.BufferedReader;
import java.io.CharArrayReader;
import java.io.CharArrayWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
/**
*
* @author andyChen
* @version 1.1 , 13/11/15
*
*/
public class CharArrayTest {
private static final String str = "abcdefghijklmnopqrstuvwxyz";
private static char[] charArray = new char[26];
static{
for(int i=0; i<str.length(); i++){
charArray[i] = str.charAt(i);
}
}
private static void testCharArrayReader() throws IOException{
CharArrayReader car = new CharArrayReader(charArray);
if(!car.ready()){
return;
}
/**
* 与ByteArrayInputStream差不多、区别就是一个字节一个字符。
* 不爽的地方在于CharArrayReader没有提供 car.available()方法、不能随时知道buf中还有多少可以读取的字符.
*/
//将写入CharArrayReader内置字符缓存数组buf中的第一个字符输出、并且标记buf下一个可读字符索引的pos++
System.out.println((char)car.read());
//读取CharArrayReader中buf字符、返回实际读取的字符数。
char[] buf = new char[5];
car.read(buf, 0, 5);
printChar(buf);
//标记当前CharArrayReader流的位置、当下次调用reset后继续使用CharArrayReader读取时从此标记的位置开始读取。
//即用 markedPos记录当前的pos
car.mark(0);
//丢弃从buf下一个将要读取的字符开始的10个字符、返回实际丢弃的字符。
car.skip(10);
//读取10个字符
char[] buf2 = new char[10];
car.read(buf2, 0, 10);
printChar(buf2);
//查看buf中是否还有有效可供读取的字符
System.out.println(car.ready());
//重置mark标记的位置、即将markedPos的值重新赋给pos、这样当读取下一个字符时就是读取buf的索引为pos的字符。
car.reset();
System.out.println((char)car.read());
}
private static void testCharArrayWriter() throws IOException{
File file = new File("D:\\caw.txt");
CharArrayWriter caw = new CharArrayWriter();
//将第一个 a-z 字符写入caw内置buf中
for(int i=0; i<charArray.length; i++){
caw.write(charArray[i]);
}
caw.write("\r\n");
//将第二个a-z字符写入caw内置buf中
caw.write(charArray, 0, charArray.length);
caw.write("\r\n");
//将第三个a-z字符写入buf中
caw.write(charArray);
caw.write("\r\n");
//将第四个a-z字符写入buf中
caw.write(new String(charArray), 0, charArray.length);
caw.write("\r\n");
//将第五个a-z字符写入buf中
for(int i=0; i<charArray.length; i++){
caw.append(charArray[i]);
}
caw.append("\r\n");
//此方法传入的是一个CharSequence、CharArray是一个CharSequence的一个子类、但是为什么不行?
//caw.append(charArray);
//caw.append("\r\n");
//将第六个a-z字符写入buf中
caw.append(new StringBuffer(new String(charArray)));
caw.append("\r\n");
/**
* 简单说明:caw.append()传入的参数时CharSequence、char
* 但是上面传入的String、StringBuffer、StringBuilder也行、很简单、他们是CharSequence接口的实现类。
*/
String aboveResult = caw.toString();
char[] buf = caw.toCharArray();
System.out.println("String aboveResult: "+ "\r\n" + aboveResult);
System.out.println("=====================================");
System.out.println("char[] result : " + "\r\n" +new String(buf));
FileWriter fw = new FileWriter(file);
caw.writeTo(fw);
fw.flush();
fw.close();
}
/**
* 将写入文件的中文读取出来
* 这里没有什么组织性、
* 自己可以尝试不同组合的读取、加深理解。
*/
private static void test() throws FileNotFoundException, IOException {
File file = new File("D:\\bos.txt");
FileOutputStream fos = new FileOutputStream(file);
FileInputStream fis = new FileInputStream(file);
fos.write("陈华应".getBytes());
fos.flush();
fos.close();
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
char[] cbuf = new char[fis.available()];
br.read(cbuf);
CharArrayReader car = new CharArrayReader(cbuf);
char[] newCbuf = new char[fis.available()];
car.read(newCbuf);
System.out.println(new String (newCbuf));
}
private static void printChar(char[] buf){
for(char c : buf ){
System.out.print(c);
}
System.out.println();
}
public static void main(String[] args) throws Exception{
testCharArrayWriter();
testCharArrayReader();
test();
}
}
总结:
本质是将字符写入内置字符缓存数组中、或者是将字符从内置缓存数组读取到程序中(内置字符缓存数组中字符的来源是在构造CharArrayReader时传入的字符数组)。