关于IO包装流中的两个read方法

刚开始学IO流,会经常感到奇怪,为什么read方法返回的都是int类型,而且,在包装流中经常会弄混淆,看了传智播客老师的视频,加上API文档的了解,总算是完全弄懂了。

下面贴出四个包装流的代码,分别包装了inputstream、outputstream、reader、writer:

public class MyBufferedInputStream extends InputStream {

	private InputStream in;
	private byte[] buf = new byte[1024];	//自定义字节数组作为缓冲区
	private int len = 0; 	//定义一个变量,用于记住缓冲区可用字节数量
	private int pos = 0; 	//定义一个变量,用于记住缓冲区当前可用字节的角标
	//通过构造函数组合被包装的流
	public MyBufferedInputStream(InputStream in) {
		this.in = in;
	}
	
	@Override
	public int read() throws IOException {
		//判断缓冲区是否还有可用字节
		if(len==0) {
			//一次性填充缓冲区
			len = in.read(buf);
			//pos要置零
			pos = 0;
		}
		//判断是否到了流的末尾
		if(len==-1) {
			return -1;
		}
		//返回一个字节,可用字节就少一个,所以len到减1
		len--;
		//返回当前可用字节,升级为int,前面加24个0
		//11111111 & 00000000 00000000 00000000 11111111 0xff
		return buf[pos++]&0xff;
	}
	
	public void close() throws IOException {
		//关闭底层被包装的流
		in.close();
	}

}


public class MyBufferedOutputStream extends OutputStream {

	private OutputStream out;
	private byte[] buf = new byte[1024];	//自定义缓冲区
	private int pos = 0; 	//定义一个变量,记住当前缓冲区可存储的位置
	//组合被包装的流
	public MyBufferedOutputStream(OutputStream out) {
		this.out = out;
	}
	@Override
	public void write(int b) throws IOException {
		//判断缓冲区是否已满
		if(pos==1024) {
			//刷新缓冲区
			flush();
			//pos置零
			pos = 0;
		}
		//将当前字节存入缓冲区对应的空位
		buf[pos++] = (byte) b;
	}
	
	public void flush() throws IOException {
		//将缓冲区有用的字节写入底层流
		out.write(buf, 0, pos);
	}

	public void close() throws IOException {
		//刷心缓冲区
		flush();
		//关闭底层的流
		out.close();
	}
}

public class MyBufferedReader extends Reader {
	private Reader r;
	private char[] buf = new char[1024];
	private int pos;
	private int len;
	public MyBufferedReader(Reader r) {
		this.r = r;
	}
	
	/* 实现read方法,实现缓冲的功能
	 * 分析:
	 * 1.当别人第一次调用次方法时,一次性填充缓冲区
	 * 2.定义一个变量len记住缓冲区的可用字符数量
	 * 3.定义一个变量pos用于记住当前可用字符的角标
	 * 3.将数组的第一个元素返回,
	 * 4.当别人第二次调用时,将数组的第二个元素返回,
	 * 5.每次返回一个元素,len--
	 * 6.当len为0时,说明数组没有可用字符了,再次填充缓冲区,直到读到-1,
	 * 
	 * 思路:
	 * 1.定义两个成员变量,len记住可用字符数量,pos记住当前可用字符的位置
	 * 2.判断len,如果len为0,填充缓冲区,pos要置零
	 * 3.判断len,如果为-1,我们也返回-1
	 * 4.将pos位置的元素返回,pos要++
	 */
	public int read() throws IOException {
		if(len==0) {
			len = r.read(buf);
			pos = 0;
		}
		if(len==-1)
			return -1;
		len--;
		return buf[pos++];
	}
	
	/* 实现readLine方法,实现读一行的功能
	 * 1.循环调用自己的read方法,读取字符
	 * 2.直到遇上回车换行,方法结束
	 */
	public String readLine() throws IOException {
		StringBuilder sb = new StringBuilder();
		int ch;
		while((ch=read())!=-1) {
			if(ch=='\r')
				continue;
			if(ch=='\n')
				break;
			sb.append((char)ch);
		}
		if(ch==-1&&sb.length()==0)
			return null;
		return sb.toString();
	}
	
	public void close() throws IOException {
		r.close();
	}

	@Override
	public int read(char[] buf, int offset, int len) throws IOException {
		int count = 0;
		for(int i=offset; i<offset+len; i++) {
			int ch = read();
			if(ch==-1)
				break;
			count++;
			buf[i] = (char) ch;
		}
		return count;
	}
}

public class MyBufferedWriter extends Writer {
	
	private Writer w;
	private char[] buf = new char[1024];
	private int pos = 0;
	public MyBufferedWriter(Writer w) {
		this.w = w;
	}

	/*
	 * 定义write方法,实现写入一个字符,实现缓冲的功能
	 * 1.定义一个变量pos记住当前的写入位置,
	 * 2.每次调用者调用此方法都会传入一个字符,将字符存入缓冲数组的pos位置,
	 * 3.pos++;
	 * 4.每次一上来都要判断,如果pos==1024,刷新缓冲区,pos=0;
	 */
	public void write(int ch) throws IOException {
		if(pos==1024) {
			flush();
			pos = 0;
		}
		buf[pos++] = (char) ch;
	}
	
	@Override
	public void close() throws IOException {
		flush();
		w.close();
	}

	@Override
	public void flush() throws IOException {
		// 刷新缓冲区,将当前缓冲区有用字符一次性写入底层被包装的流
		w.write(buf, 0, pos);
	}

	public void write(String data) throws IOException {
		char[] chars = data.toCharArray();
		for(char c : chars)
			write(c);
	}
	
	public void newLine() throws IOException {
		write("\r\n");
	}
	@Override
	public void write(char[] buf, int offset, int len) throws IOException {
		for(int i=offset; i<offset+len; i++)
			write(buf[i]);
	}

}

所有这些包装流中,无参的read()方法,返回的int都是字符或字节的ASCII码,参数为数组的read(buf)返回的int是数组中的字符或字节个数,用来确定读取到的字符或字节在数组中的位置,两个read方法返回-1时都代表到了流的末尾。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值