Java_io体系之CharArrayReader、CharArrayWriter简介、走进源码及示例——13

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、实例演示:


            参见下面的实例演示、一般喜欢将两者放在一个测试类中、分成两个方法testCharArrayReader()、testCharArrayWriter()、有关联的两个类还会多出关联测试、这样有条理点。

二: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时传入的字符数组)。


更多IO内容:java_io 体系之目录


你可能感兴趣的:(java,源码,Inputstream,OutputStream,IO流)