简介
CharArrayWriter和CharArrayReader分别是字符数组输出流和字符数组输入流,与ByteInputStream和ByteOutputStream字节数组流相比,前者是缓冲区里面存储的是字符,而字节数组里面存储是字节.
- CharArrayWriter---字符数组输出流里面有一字符数组(缓冲区),写入字符数组流的数据会存储在此字符数组中,如果字符数据超过了缓冲区的大小,就会扩容.写入流里面的数据可以通过调用方法toString()或者toCharArray()方法查看.
- CharArrayReader---字符数组输入流里面有一字符数组(缓冲区),通过有参构造方法将字符数据写入缓冲区,通过调用方法可以读取到缓冲区指定位置的数据.
CharArrayWriter介绍
1.构造方法
public CharArrayWriter() {}
public CharArrayWriter(int initialSize) {}
- 无参构造,创建缓冲区为默认的32个字符
- 有参构造,创建指定大小initialSize的缓冲区
2.内部变量
protected char buf[];
protected int count;
- buf---字符数组输出流中缓冲区,为一字符数组.
- 缓冲区中有效字符的大小.
3.内部方法
public void write(int c) {}
public void write(char c[], int off, int len) {}
public void write(String str, int off, int len) {}
public void writeTo(Writer out) throws IOException {}
public CharArrayWriter append(CharSequence csq) {}
public CharArrayWriter append(CharSequence csq, int start, int end) {}
public CharArrayWriter append(char c) {}
public void reset() {}
public char toCharArray()[] {}
public int size() {
public String toString() {}
- write(int c)---将字符c写到字符数组输出流中.
- write(char c[] ,int off,int len)---将字符数组c中off位置开始,len个字节写到字符数组输出流中.
- write(String str,int off,int len)---将字符串中,off位置开始,len个字符写到字符数组输出流中.
- writeTo(Writer out)---将缓冲区中的数据写到另外一个字符输出流中.
- append(CharSequence csq)---将字符序列csq写到字符数组输出流中.并返回CharArrayWriter对象
- append(CharSequence csq,int start ,int end)---将字符序列csq中start到end之间的字符写到数组数组输出流中.并返回CharArrayWriter对象
- append(char c)---将字符c添加到缓冲区中,并返回CharArrayWriter对象.
- reset()---清空缓冲区.
- toCharArray()[]---将缓冲区中数据复制字符数组中,并返回.
- size()---返回缓冲区的大小.
- toString()---将缓冲区里面的数据转换成字符串返回.
CharArrayReader介绍
1.构造方法
public CharArrayReader(char buf[]) {}
public CharArrayReader(char buf[], int offset, int length) {}
- 创建指定缓冲区的字符数组输入流.
- 创建指定缓冲区的字符数组输入流.(会将流中位置和标记的位置都置为offset索引处).
2.内部变量
protected char buf[];
protected int pos;
protected int markedPos = 0;
protected int count;
- buf---字符数组输入流中缓冲区位字符数组
- pos---流中当前位置.
- markpos---标记位置,调用mark()方法会将当前位置保存到markPos位置,调用reset()方法会将当前重置到markpos位置.
- count---缓冲区结尾的索引值.
3.内部方法
public int read(){}
public int read(char b[], int off, int len){}
public long skip(long n){}
public boolean ready(){}
public boolean markSupported(){}
public void mark(int readAheadLimit) {}
public void reset(){}
public void close()
- read()---读取一个字符.
- read(char b[],int off,int len)---将流中最多读取len个字节到字节数组b中.位置从off开始.
- skip(long n)---缓冲区当前位置跳过n个字节,实际跳过的字节小于n.
- ready()---是否能读取下一个字节.
- markSupported()---是否支持标记.
- mark(int readAheadLimit)---标记缓冲区当前位置.保存当前位置索引.
- reset()---将流中当前位置重置到最后一次标记的位置.
- close()---关闭流,释放相关资源.
案例
public class CharArrayDemo {
public static void main(String[] args) throws IOException {
char[] letters = new char[] {'b','c','d','e','f','h','i','j'};
testCharArrayWriter(letters);
System.out.println("-----------------------------");
testCharArrayReader(letters);
}
//测试testCharArrayWriter
private static void testCharArrayWriter(char[] letters) throws IOException {
CharArrayWriter caw = new CharArrayWriter();
caw.write('a');
caw.write(letters,0,4);
caw.write("world", 1, 3);
caw.append('0').append("123").append("678910", 0, 2);
String result = caw.toString();
System.out.println("缓冲区数据转化成字符串---"+result);
char[] charArray = caw.toCharArray();
System.out.println("缓冲区数据---"+new String(charArray).toString());
CharArrayWriter anotherWriter = new CharArrayWriter();
caw.writeTo(anotherWriter);
System.out.println("字符数组anotherWriter的数据"+anotherWriter.toString());
}
//测试testCharArrayReader
private static void testCharArrayReader(char[] letters) throws IOException {
CharArrayReader car = new CharArrayReader(letters);
//下一个字节是否可读
if(car.ready()) {
System.out.println("单个字节---"+(char)car.read());
}
char[] letterChar = new char[10];
car.read(letterChar, 0, 3);
System.out.println("字符数组letterChar--"+String.valueOf(letterChar));
//mark(0),0不表示实际意义,mark的是当前位置
if(car.markSupported()) {
car.mark(0);
}
//跳过三个字节
car.skip(3);
System.out.println("此时位置----"+(char)car.read());
car.reset();
System.out.println("此时位置----"+(char)car.read());
}
}
运行结果:
缓冲区数据转化成字符串---abcdeorl012367
缓冲区数据---abcdeorl012367
字符数组anotherWriter的数据abcdeorl012367
-----------------------------
单个字节---b
字符数组letterChar--cde
源码分析
1.CharArrayWriter源码分析
public class CharArrayWriter extends Writer {
//CharArrayWriter里面缓冲区是一个字符数组
protected char buf[];
//缓冲区里面有效字符数
protected int count;
//创建一个CharArrayWriter对象,默认缓冲区大小为32
public CharArrayWriter() {
this(32);
}
//创建一个指定大小initialSize的缓冲区的CharArrayWriter对象.
public CharArrayWriter(int initialSize) {
if (initialSize < 0) {
throw new IllegalArgumentException("Negative initial size: "
+ initialSize);
}
buf = new char[initialSize];
}
//将一个字符写到CharArrayWriter的缓冲区中
public void write(int c) {
synchronized (lock) {
int newcount = count + 1;
if (newcount > buf.length) {
buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newcount));
}
buf[count] = (char)c;
count = newcount;
}
}
//将字符数组c中off位置开始,len个字节写到CharArrayWriter的缓冲区中.
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;
}
}
//将字符串str里面里面off位置开始len个字符写到缓冲区中
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;
}
}
//将缓冲区的数据写到另外一个字符输出流中
public void writeTo(Writer out) throws IOException {
synchronized (lock) {
out.write(buf, 0, count);
}
}
//将字符序列csq数据添加CharArrayWriter里面,返回CharArrayWriter对象
public CharArrayWriter append(CharSequence csq) {
String s = (csq == null ? "null" : csq.toString());
write(s, 0, s.length());
return this;
}
//将字符序列csq中start位置开始到end之间的数据添加到CharArrayWriter的缓冲区里面.返回CharArrayWriter对象
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;
}
//添加一个字符添加到缓冲区里面,并返回此字符数组输出流对象.
public CharArrayWriter append(char c) {
write(c);
return this;
}
//清空缓冲区的数据
public void reset() {
count = 0;
}
//将缓冲区的数据复制到字符数组,返回字符数组.
public char toCharArray()[] {
synchronized (lock) {
return Arrays.copyOf(buf, count);
}
}
//返回缓冲区有效字符的大小
public int size() {
return count;
}
//将缓冲区数据转换成字符串
public String toString() {
synchronized (lock) {
return new String(buf, 0, count);
}
}
//刷新缓冲区
public void flush() { }
//关闭流
public void close() { }
}
2.CharArrayReader源码分析
public class CharArrayReader extends Reader {
//字符数组输入流的缓冲区buf
protected char buf[];
//缓冲区中当前的位置
protected int pos;
//缓冲区标记的位置
protected int markedPos = 0;
//缓冲区结尾的索引值
protected int count;
//创建指定缓冲数组的字符输入流
public CharArrayReader(char buf[]) {
this.buf = buf;
this.pos = 0;
this.count = buf.length;
}
//创建一个指定缓冲数组的字符输入流.
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;
}
/** Checks to make sure that the stream has not been closed */
//确保流还没有被关闭
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++];
}
}
//将缓冲区中的数据读取到字符数组b的off位置开始,长度为len个字符.
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;
}
if (pos >= count) {
return -1;
}
//剩余可读取的字符数avail,实际可能只能读取到avail个
int avail = count - pos;
if (len > avail) {
len = avail;
}
if (len <= 0) {
return 0;
}
//将缓冲区字符数组buf中len字节复制到字符数组b中
System.arraycopy(buf, pos, b, off, len);
pos += len;
return len;
}
}
//跳过n个字节.实际跳过的字节要看剩余可读取的字节数.
//n为负数情况下,返回0
public long skip(long n) throws IOException {
synchronized (lock) {
ensureOpen();
//实际剩余要读取的字节数
long avail = count - pos;
if (n > avail) {
n = avail;
}
if (n < 0) {
return 0;
}
pos += n;
return n;
}
}
//是否能读取下一个字节
public boolean ready() throws IOException {
synchronized (lock) {
ensureOpen();
return (count - pos) > 0;
}
}
//是否支持标记
public boolean markSupported() {
return true;
}
//标记当前位置,保存当前位置的索引
public void mark(int readAheadLimit) throws IOException {
synchronized (lock) {
ensureOpen();
markedPos = pos;
}
}
//将当前位置重置到最后一次标记位置
public void reset() throws IOException {
synchronized (lock) {
ensureOpen();
pos = markedPos;
}
}
//关闭流,释放相关资源
public void close() {
buf = null;
}
}
总结
字符数组输入流和输出流,不是从文件读取和写入到文件的流,字符数组输出流中存在缓冲区,通过调用write()或者append()方法向缓冲区中写入字符数据,当数据超过缓冲区时,会扩容。而字符数组输入流,通过有参构造方法传入字符数组创建缓冲区,调用read(),mark()等方法可以返回缓冲区指定位置索引的数据。