黑马程序员————IO流------(2)

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------


BufferedWriter:

缓冲区的出现是为了提高流的操作效率而出现的。所以在创建缓冲区之前,必须要先有流对象。该缓冲区中提供了一个跨平台的换行符newLine();

练习:

package IO;
import java.io.*;
public class BufferedWriterDemo {
	public static void main(String[] args)throws Exception {
		//实例化一个字符写入流
		Writer w=new FileWriter("e:/a.txt");
		//给字符写入流包装一下,提高效率
		BufferedWriter bw=new BufferedWriter(w);
		bw.write("abc");
		bw.newLine();//换行符
		bw.write("efg");
		bw.flush();
		bw.close();//关闭资源
	}
}
BufferedReader:
字符读取流缓冲区:该缓冲区可以进行读一行操作,方便对文件的读取。当返回Null时,就读到末尾了。

练习:

package IO;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.Reader;

public class BufferedReaderDemo {
	public static void main(String[] args)throws Exception {
		//创建一个读取流对象和文件关联
		Reader r=new FileReader("e:/a.txt");
		//加入缓冲技术,提高效率,与读取流对象关联起来
		BufferedReader bw=new BufferedReader(r);
		String line=null;
		while((line=bw.readLine())!=null){
			System.out.println(line);
		}
<span style="white-space:pre">		</span>bw.colse();
	}
}


练习:

要求:通过缓冲区复制文本文件

package IO;
/*
 * 思路:
 * 1.先有读取流和需要被复制的文件关联,然后加入缓冲区
 * 2.有一个写入流和目的文件相关联,然后加入缓冲区
 * 3.一边读取一行,一边写进一行,这样就能完成复制
 */
import java.io.*;
public class CopyFile {
	public static void main(String[] args)throws Exception {
		//读取流
		BufferedReader br=new BufferedReader(new FileReader("e:/CopyFile.java"));
		//写入流
		BufferedWriter bw=new BufferedWriter(new FileWriter("e:/copy.txt"));
		//一边读,一边写
		String line=null;
		while((line=br.readLine())!=null){
			bw.write(line);
			bw.newLine();
			bw.flush();
		}
		bw.close();
		br.close();
	}
}

readLine的原理

将读到的\r\n时,就将数组中的已有数据打印出来。然后继续读下一行的元素。

模拟readLine功能写一个自己的MyBufferedReader

代码:

package IO;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.io.Reader;

/*
 * 思路:
 * 1.readLine的原理就是读到\r\n时,才把所读到的所有存进缓冲区。
 * 2.知道原理后,自己可以写一个BufferedReader
 */
public class MyBufferedReader {
	private FileReader r;
	public MyBufferedReader(FileReader r){
		this.r=r;
	}
	//为了方便,这里定义StringBuilder容器,因为最终还是要将数组转换成字符串
	public String myReadLine()throws Exception{
		StringBuilder sb=new StringBuilder();
		int ch=0;
		while((ch=r.read())!=-1){
			if(ch=='\r')
				continue;
			if(ch=='\n')
				return sb.toString();
			else
				sb.append((char)ch);//这点很重要,记得要强制转换成char,不然复制出来全是数字。
		}
		if(sb.length()!=0){//如果最后一行没有换行符,它就导致最后一行存进缓冲区,没被返回。所有自己判断一下
			return sb.toString();
		}
		return null;
		
	}
	public void myClose()throws Exception{
		r.close();
	}
	public static void main(String[] args){
		MyBufferedReader mbr=null;
		BufferedWriter bw=null;
		try {
			 mbr=new MyBufferedReader(new FileReader("e:/copy.txt"));
			 bw=new BufferedWriter(new FileWriter("e:/copy_1.txt"));
			 String line=null;
			 while((line=mbr.myReadLine())!=null){//运用自己的读一行的方法
				bw.write(line);
				bw.newLine();
				bw.flush();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			try{
				if(mbr!=null){
					mbr.myClose();
				}
			}catch(Exception e){
				e.printStackTrace();
			}
			try{
				if(bw!=null){
					bw.close();
				}
			}catch(Exception e){
				e.printStackTrace();
			}
			
		}
	}
}

注意:最后一行可能没有换行符,那么数据也只是存到缓冲区,并没有被返回,所有最好进行自己的判断,返回。

if(sb.length()!=null){

retren sb.toString();

}


装饰者设计模式

将被增强的对象,传给增强的对象,基于原本的读一个的功能,扩展为读一行的功能。

装饰类通常通过构造方法接收被装饰的对象,并基于被装饰的对象的功能,提供更强大的功能。

实例:

package IO;

public class Decorator {
	Student s;
	public Decorator(Student s){
		this.s=s;
	}
	public void sleep(){
		System.out.println("看书");
		System.out.println("听歌");
		s.sleep();
	}
}
class Student{
	public void sleep(){
		System.out.println("睡觉");
	}
}

装饰和继承的区别

如读这个体系,有读文本,读照片,读电影等,不可能每个类都继承Buffer,那么这样会造成这个体系太臃肿,且扩展性不强,这时可以直接定义一个装饰类(Buffer),把读文件等类作为参数传入,这样就具备了Buffer的增强功能。


装饰者模式就是为已有功能加强的,还是原来的体系中的类。


装饰者比继承要灵活,降低了类与类直接的关系。

自定义装饰类

package IO;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Reader;
/*
 * 这就是一个装饰类,还是属于Reader体系中
 * 它继承了Reader,复写了Reader中的方法,也加强了read方法,使原来读一个变为读一行
 */
public class MyBufferedReader extends Reader {
	private FileReader r;
	public MyBufferedReader(FileReader r){
		this.r=r;
	}
	//为了方便,这里定义StringBuilder容器,因为最终还是要将数组转换成字符串
	public String myReadLine()throws Exception{
		StringBuilder sb=new StringBuilder();
		int ch=0;
		while((ch=r.read())!=-1){
			if(ch=='\r')
				continue;
			if(ch=='\n')
				return sb.toString();
			else
				sb.append((char)ch);//这点很重要,记得要强制转换成char,不然复制出来全是数字。
		}
		if(sb.length()!=0){//如果最后一行没有换行符,它就导致最后一行存进缓冲区,没被返回。所有自己判断一下
			return sb.toString();
		}
		return null;
		
	}
	@Override
	public int read(char[] cbuf, int off, int len) throws IOException {
		return r.read(cbuf, off, len);
	}
	@Override
	public void close() throws IOException {
		r.close();
	}
	
}


拷贝图片

不要用字符流来拷贝媒体文件,字符流是用来处理文字数据的。

package IO;
import java.io.*;
public class CopyPic {
	public static void main(String[] args)throws Exception {
		FileInputStream fis=new FileInputStream("e:/2.png");
		FileOutputStream fos=new  FileOutputStream("e:/copy_pic.png");
		int len=0;
		while((len=fis.read())!=-1){
			fos.write(len);
		}
		fis.close();
		fos.close();
	}
}


自定义字节流的缓冲区--read和write的特点

先从硬盘上抓上一把数据,再存到数组缓冲区去,然后通过指针,一个一个读出来。取完之后,再取硬盘中抓一把数据,再存到数组中去。再通过指针取。

package IO;

/*
 * 定义数组:当做缓冲区,存放从硬盘中读取来的数据
 * 定义指针:从数组中一个一个的读取出来
 * 定义计数器:当数组中的数据读完,计数器显示为0 ,这时继续从硬盘中读取
 */
import java.io.*;

public class MyBufferedInputStream {
	private InputStream ins;
	byte[] buf = new byte[1024];
	private int pos = 0;// 定义指针
	private int count = 0;// 用来判断缓冲区数据是否读完

	private MyBufferedInputStream(InputStream ins) {
		this.ins = ins;
	}

	// 一次读一个自己 从字符缓冲区(数组)中获取
	public int myRead() throws Exception {
		if (count == 0) {// 当数组中的数据读完时
			pos = 0;
			count = ins.read(buf);
			if (count == -1)
				return -1;
			byte b = buf[pos];
			count--;
			pos++; // 从数组读数据,自动从Byte提升int
			return b & 255;// 防止出现-1的情况,导致文件复制不成功
		}
		else if(count>0){
			byte b=buf[pos];
			count--;
			pos++;
			return b & 0xff;
		}
	       return -1;
  }
	public void myClose()throws Exception{
		ins.close();
	}
	
	public static void main(String[] args)throws Exception{
		MyBufferedInputStream fis=new MyBufferedInputStream(new FileInputStream("e:/copy.txt"));
		FileOutputStream fos=new FileOutputStream("e:/copy_c.txt");
		int b=0;
		while((b=fis.myRead())!=-1){
		    fos.write(b);
		}
		fos.flush();
		fos.close();
		fis.myClose();
	}
}


读取键盘的录入

System.in对应键盘的输出设备,控制台

System.out:对应标准输入设备:键盘

注意:Read是阻塞式方法。

需求:

通过录入一行数据,然后打印出来。直到录入为over,那就停止录入。

package IO;

import java.io.*;

public class SystemDemo {
	public static void main(String[] args) throws Exception {
		InputStream ins = System.in;
		StringBuffer sb = new StringBuffer();// 把数据先存入里面
		int b = 0;
		while (true) {
			b = ins.read();
			if (b == '\r')
				continue;
			if (b == '\n') {
				if ("over".equals(sb.toString())) {
					break;
				}
				System.out.println(sb.toString());
				sb.delete(0, sb.length());
			} else {
				sb.append((char) b);
			}
		}
	}
}

运行结果:



读取转换流

操作字节流的字符流InputStreamReader.

怎么来的呢?实际是因为字节流没有读一行的方法,而字符流有这方法,我想要使用,那么我就必须变为字符流才可以。

package IO;
import java.io.*;
/*
 * 因为BufferedReader有读一行的方法,那么把字节流转换为字符流,
 * 再提高效率后,就能使用这个方法readLine();
 */
public class TransStreamDemo {
	public static void main(String[] args) throws Exception {
		//键盘录入对象
		InputStream ins=System.in;
		//字节流转换为字符流
		InputStreamReader irs=new InputStreamReader(ins);
		//提高效率
		BufferedReader br=new BufferedReader(irs);
		
		String line=null;
		while((line=br.readLine())!=null){
			if("over".equals(line)){
				break;
			}else
				System.out.println(line);
			
		}
		
		
	}
}


写入转换流

字符流通向字节的桥梁:OutputStreamWriter.

 文件以字节的形式存在,录入的是字符,存在硬盘的是字节。字符输出流内部是缓冲区,要flush 


package IO;
import java.io.*;
/*
 * 因为BufferedReader有读一行的方法,那么把字节流转换为字符流,
 * 再提高效率后,就能使用这个方法readLine();
 */
public class TransStreamDemo {
	public static void main(String[] args) throws Exception {
		//键盘录入对象
		InputStream ins=System.in;
		//字节流转换为字符流
		InputStreamReader irs=new InputStreamReader(ins);
		//提高效率
		BufferedReader br=new BufferedReader(irs);
		
		//写入转换流
		BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(System.out));
		String line=null;
		while((line=br.readLine())!=null){
			if("over".equals(line)){
				break;
			}else
				bw.write(line);
				bw.newLine();
				bw.flush();
		}
		
		
	}
}


流操作规律

通过三个明确来完成。

   1.明确源和目的

源:输入流。InputStream  Reader

目的:输出流。OutputStrema Writer

    2.操作的数据是否是纯文本

是:字符流

不是:字节流

    3.当体系明确后,在明确要使用哪个具体的对象。

通过设备来区分

源设备:内存,硬盘,键盘

目的设备:内存,硬盘,控制台。


当涉及到字符编码转换时,需要用到转换流。


改变标准流输入输出设备

System.setIn(new FileInputStream());

System.setOut(new FileOutputStream());



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值