前两篇文章Java8 I/O源码-Reader与Writer简单介绍了Reader和Writer。本文将详细介绍CharArrayReader与CharArrayWriter,拉开学习字符型输入流的序幕。
CharArrayReader实现一个可用作字符输入流的字符缓冲区。支持mark/set。
CharArrayWriter实现一个可用作字符输出流的字符缓冲区。缓冲区会随向流中写入数据而自动增长。可使用 toCharArray()和 toString()获取数据。
CharArrayReader
public class CharArrayReader extends Reader {
/** 字符缓冲区 */
protected char buf[];
/** 缓冲区中下一个被获取的字符的索引 */
protected int pos;
/** The position of mark in buffer. */
protected int markedPos = 0;
/** 字符缓冲区大小 **/
protected int count;
/**
* 根据指定的char数组创建一个CharArrayReader。
*
* buf不是复制得到的
*/
public CharArrayReader(char buf[]) {
this.buf = buf;
this.pos = 0;
this.count = buf.length;
}
/**
* 根据指定的char数组创建一个CharArrayReader。
*
* @throws IllegalArgumentException 如果offset为负或大于buf.length,或者length为负,或者这两个值的和为负。
*
* @param buf 输入缓冲区(不是复制得到的)
* @param offset 要读取的第一个char在buf中的索引/偏移量
* @param length 要读取的char数目
*/
public CharArrayReader(char buf[], int offset, int length) {
//如果offset为负或大于buf.length,或者length为负,或者这两个值的和为负,抛出IllegalArgumentException。
if ((offset < 0) || (offset > buf.length) || (length < 0) ||
((offset + length) < 0)) {
throw new IllegalArgumentException();
}
this.buf = buf;
this.pos = offset;
//count为length或buf.length-offset其中的较小者
this.count = Math.min(offset + length, buf.length);
this.markedPos = offset;
}
/** 检查流是否被关闭。若字符缓冲为null,则认为流已关闭。*/
private void ensureOpen() throws IOException {
if (buf == null)
throw new IOException("Stream closed");
}
/**
* 读取单个字符。
* 如果到达缓冲区末尾,返回-1
*/
public int read() throws IOException {
synchronized (lock) {
ensureOpen();
if (pos >= count)
return -1;
else
return buf[pos++];
}
}
/**
* 读取数据,并保存到字符数组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;
}
if (pos >= count) {
return -1;
}
if (pos + len > count) {
len = count - pos;
}
if (len <= 0) {
return 0;
}
System.arraycopy(buf, pos, b, off, len);
pos += len;
return len;
}
}
/**
* 跳过字符。
* 返回跳过的字符数。
*/
public long skip(long n) throws IOException {
synchronized (lock) {
ensureOpen();
if (pos + n > count) {
n = count - pos;
}
if (n < 0) {
return 0;
}
pos += n;
return n;
}
}
/**
* 判断此流是否已准备好被读取。
*/
public boolean ready() throws IOException {
synchronized (lock) {
ensureOpen();
return (count - pos) > 0;
}
}
/**
* 判断此流是否支持mark()操作
* CharArrayReader支持mark()操作。
*
*/
public boolean markSupported() {
return true;
}
/**
* 标记流中的当前位置。
* 对reset()的后续调用会将该流重新定位到此点。
*/
public void mark(int readAheadLimit) throws IOException {
synchronized (lock) {
ensureOpen();
markedPos = pos;
}
}
/**
* 将该流重置为最新的标记。
* 如果从未标记过,则将其重置到开头。
*
* @exception IOException If an I/O error occurs
*/
public void reset() throws IOException {
synchronized (lock) {
ensureOpen();
pos = markedPos;
}
}
/**
* 关闭该流并释放与之关联的所有系统资源。
*/
public void close() {
buf = null;
}
}
demo
import java.io.CharArrayReader;
import java.io.IOException;
import org.junit.Test;
public class CharArrayReaderTest {
/**
* CharArrayReader的API测试函数
*/
@Test
public void tesCharArrayReader() {
try {
CharArrayReader reader = new CharArrayReader(
new char[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h' });
// 从reader中连续读取三个字节
for (int i = 0; i < 3; i++) {
if (reader.ready() == true) {
char tmp = (char) reader.read();
System.out.print(tmp);
}
}
System.out.println();
// 测试是否支持mark
if (!reader.markSupported()) {
System.out.println("make not supported!");
return;
} else
System.out.println("make supported!");
// 标记,当前位置为d
reader.mark(0);
// 跳过2个字符,当前位置为f
reader.skip(2);
// 向下读取两个字符,fg
char[] buf = new char[2];
reader.read(buf, 0, 2);
System.out.println("buf:" + String.valueOf(buf));
// 重置当前位置为上一次标记的位置,即为d
reader.reset();
// 向下读取两个字符,de
reader.read(buf, 0, 2);
System.out.println("buf:" + String.valueOf(buf));
// 关闭后,在调用方法,会抛出“java.io.IOException: Stream closed”异常
reader.close();
reader.read();
} catch (IOException e) {
e.printStackTrace();
}
}
}
执行方法后,控制台打印结果为:
abc
make supported!
buf:fg
buf:de
java.io.IOException: Stream closed
总结
- CharArrayReader实现一个可用作字符输入流的字符缓冲区。
- 在做所有操作前,都要确认流处于open状态。判断流处于open状态的依据是buf不为null。close方法中会将buf置为null。
- CharArrayReader支持mark()操作。
CharArrayWriter
public class CharArrayWriter extends Writer {
/**
* 存储数据的字符缓冲区
*/
protected char buf[];
/**
* 缓冲区中的字符个数
*/
protected int count;
/**
* 创建一个新的CharArrayWriter。
* 缓冲区大小默认为32
*/
public CharArrayWriter() {
this(32);
}
/**
* 创建一个新的CharArrayWriter,指定缓冲区大小为initialSize
* 如果initialSize为负数,抛出异常
*/
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] = (char)c;
count = newcount;
}
}
/**
* 将字符数组c中从off开始的len个字符写入到缓冲区中。
*/
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;
//如果buf存满、则将buf容量扩大1倍、并将原来buf中count字符copy到新的buf中
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;
//如果buf存满、则将buf容量扩大1倍、并将原来buf中count字符copy到新的buf中
if (newcount > buf.length) {
buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newcount));
}
str.getChars(off, off + len, buf, count);
count = newcount;
}
}
/**
* 将缓冲区的内容写入另一个字符流out。
*/
public void writeTo(Writer out) throws IOException {
synchronized (lock) {
out.write(buf, 0, count);
}
}
/**
* 将指定的字符序列添加到此writer。
*/
public CharArrayWriter append(CharSequence csq) {
String s = (csq == null ? "null" : csq.toString());
write(s, 0, s.length());
return this;
}
/**
* 将指定字符序列的子序列添加到此 writer。
* @since 1.5
*/
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;
}
/**
* 将指定字符添加到此writer。
* @since 1.5
*/
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() { }
}
deom
import java.io.CharArrayWriter;
import java.io.IOException;
import org.junit.Test;
public class CharArrayWriterTest {
private static final char[] charArr = new char[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g'};
/**
* CharArrayWriter的API测试函数
*/
@Test
public void testCharArrayWriter() {
try {
// 创建CharArrayWriter字符流,默认大小为32
CharArrayWriter writer = new CharArrayWriter();
writer.write('A');
writer.write("BCDEF");
writer.write(charArr, 1, 3);
System.out.println("写入字符A,写入字符串BCDEF,写入charArr中从索引位置1开始的三个字符,即bcd,此时的writer为:\n" + writer);
writer.append('0').append("12345").append(String.valueOf(charArr), 3, 6);
System.out.println("写入字符0,写入字符串12345,写入charArr中从索引位置3到5的三个字符,即def,此时的writer为:\n" + writer);
System.out.println("此时writer的大小为:\n" + writer.size());
char[] buf = writer.toCharArray();
System.out.println("将writer转化为字符数组再将其打印:\n" + String.valueOf(buf));
// 创建CharArrayWriter字符流,指定大小为100
CharArrayWriter writer2 = new CharArrayWriter(100);
writer.writeTo(writer2);
System.out.println("将writer缓冲区内容写入到wirter2中,writer缓冲区内容为:\n" + writer2);
writer.reset();
System.out.println("将writer重置,此时其缓冲区为:\n" + writer);
writer2.close();
System.out.println("将writer2关闭,调用其size方法,结果为:\n" + writer2.size());
System.out.println("如果没有抛出异常,说明其close方法没有作用。");
} catch (IOException e) {
e.printStackTrace();
}
}
}
执行方法后,控制台打印内容为:
写入字符A,写入字符串BCDEF,写入charArr中从索引位置1开始的三个字符,即bcd,此时的writer为:
ABCDEFbcd
写入字符0,写入字符串12345,写入charArr中从索引位置3到5的三个字符,即def,此时的writer为:
ABCDEFbcd012345def
此时writer的大小为:
18
将writer转化为字符数组再将其打印:
ABCDEFbcd012345def
将writer缓冲区内容写入到wirter2中,writer缓冲区内容为:
ABCDEFbcd012345def
将writer重置,此时其缓冲区为:
将writer2关闭,调用其size方法,结果为:
18
如果没有抛出异常,说明其close方法没有作用。
总结
- CharArrayWriter实现一个可用作字符输出流的字符缓冲区。
- CharArrayWriter的缓冲区会随向流中写入数据而自动增长。
- 可使用CharArrayWritert的oCharArray()和 toString()获取缓冲区中数据。
- CharArrayWriter中close()方法无效。
关于CharArrayReader与CharArrayWriter就讲到这里,想了解更多内容请参考
版权声明 |
---|
作者:潘威威 原文地址:CSDN博客-潘威威的博客-http://blog.csdn.net/panweiwei1994/article/details/78324632 本文版权归作者所有,欢迎转载。转载时请在文章明显位置给出原文作者名字(潘威威)及原文链接。请勿将本文用于任何商业用途。 |