黑马程序员--- 学习笔记(第十九天)

 —————————— ASP.Net+Android+IOS开发.Net培训、期待与您交流!——————————
字符流缓冲区"
BufferedReader,BufferedWriter
缓冲区的出现是为了提高流的操作效率而出现的,所以在创建缓冲区之前,必须要
先有流对象.
BufferedWriter原理:内部封装了一个数组存储数据




记住,只要用到到缓冲区,就要记得刷新flush();


其实关闭缓冲区就是关闭缓冲区的流对象
newLine(),写入一个行分隔符,跨平台的


BufferedReader字符读取流
该缓冲区提供了一个一次读一行的方法,readLine(),不包含任何行终止符
,如果返回null,说明已到达流末尾


关闭流,关闭缓冲流即可


两个流之间是没有关系的,是通过中转站

/*
使用字符流缓冲区实现赋值一个文件
*/
import java.io.*;
class Demo1 
{
	public static void main(String[] args) 
	{
		//字符串缓冲区
		BufferedReader br=null;
		BufferedWriter bw=null;
		try
		{
			//源
			 br=new BufferedReader(new FileReader("笔.txt"));
			 //目的
			 bw=new BufferedWriter(new FileWriter("copy.txt"));

			 String line=null;
			 //读取文件内容 写入新的文件
			 while((line=br.readLine())!=null){
				bw.write(line);
				bw.newLine();
				bw.flush();
			 }
			 System.out.println("复制文件成功");
		}
		catch (IOException o)
		{
			System.out.println("复制文件失败");
		}
		finally
		{
			try
			{
				if(br!=null)
					br.close();
			}
			catch (IOException o)
			{
				System.out.println("复制文件失败");
			}
			try
			{
				if(bw!=null)
					bw.close();
			}
			catch (IOException o)
			{
				System.out.println("复制文件失败");
			}
		}
		

	}
}



readLine方法原理
无论是某一行,还是读取的字符个数,其实最终都是在硬盘上一个一个读取
,所以最终使用的还是read方法一次读取一个的方法.


原BufferedReader内部封装的是字符数组,为了演示方便,定义StringBuilder容器
,因为最终还是将数据变成字符串


/*
模拟一个BufferedReader,定义一个自己的字符读取流缓冲区

装饰设计模式
*/
import java.io.*;
class Demo2 
{
	public static void main(String[] args) 
	{
		MyBufferedReader mbr=null;
		try
		{
			mbr=new MyBufferedReader(new FileReader("Demo1.java"));
			String line=null;
			/*测试自定义读取一行的方法*/
			while((line=mbr.myReadLine())!=null){
				System.out.println(line);
			}
		}
		catch (IOException e)
		{
			System.out.println("读取文件失败");
		}
		finally
		{
			try
			{
				if(mbr!=null)
					mbr.close();
			}
			catch (IOException e)
			{
				System.out.println("读取文件失败");
			}
		}
			
	}
}
/*
装饰设计模式
*/
class MyBufferedReader extends Reader
{					    
	private Reader r;
	public MyBufferedReader(Reader r){
		this.r=r;
	}
	/**自定义读取一行方法*/
	public String myReadLine()throws IOException{
		StringBuilder sb=new StringBuilder();
		int ch=0;
		while((ch=r.read())!=-1){
			if(ch==13){
				continue;
			}
			if(ch==10){
				return sb.toString();
			}else		
				sb.append((char)ch);
		}
		if(sb.length()!=0)
			return sb.toString();
		return null;
	}
	//abstract  int read(char[] cbuf, int off, int len) 
     //     将字符读入数组的某一部分。 
	public int read(char []cbuf,int off, int len)throws IOException{
		return r.read(cbuf,off,len);
	}
	public void close()throws IOException{
		r.close();
	}
}



装饰设计模式
  当要对已有的对象进行功能增强时,可以定义一个类,将已有对象传入,基于
已有对象功能,并提供加强功能,那么自定义的该类就是装饰类


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


装饰模式比继承更灵活,避免了继承体系的臃肿,降低了类于类之间的关系


装饰类因为增加已有的对象,具备的功能和已有的功能,是相同的,只不过提供了
更强的功能,所以装饰类和被装饰类通常都是属于一个体系的



LineNumberReader
跟踪行号的缓冲字符输入流


/*
模拟一个LineNumberReader 缓冲区对象
*/
import java.io.*;
class Demo3 
{
	public static void main(String[] args) 
	{
		MyLineNumberReader ml=null;
		try
		{
			ml=new MyLineNumberReader(new FileReader("Demo1.java"));
			 ml.setLineNumber(500);//设置初始行号
			String line=null;
			/*读取*/
			while((line=ml.readLine())!=null){
				//输出行号跟内容
				System.out.println(ml.getLineNumber()+"::"+line);
			}
		}
		catch (IOException e)
		{
			System.out.println("文件读取失败");
		}
		finally
		{
			try
			{
				if(ml!=null)
					ml.close();
			}
			catch (IOException e)
			{
				System.out.println("关闭流失败");
			}
		}	
	}
}
/*
自定义BufferReader类
*/
class MyBufferedReader  extends Reader
{
	private Reader r;
	public MyBufferedReader(Reader r){
		this.r=r;
	}
	/*
	自定义读取一行方法
	*/
	public String myReadLine()throws IOException{
	   StringBuilder sb=new StringBuilder();
		int ch=0;
		while((ch=r.read())!=-1){
			if(ch==13)
				continue;
			if(ch==10)
				return sb.toString();
			else 
				sb.append((char)ch);
		}
		if(sb.length()!=0)
			return sb.toString();
	   return null;
	}
	/*复写父类关流方法*/
	public void close()throws IOException{
		r.close();
	} 
	/*复写父类的read方法*/
	public int read(char []ch,int off, int len)throws IOException{
		return r.read(ch,off,len);
	}
}
/*
自定义LineNumberReader
*/
class MyLineNumberReader  extends MyBufferedReader
{
	private Reader r;
	private int lineNumber;	//行号
	public void setLineNumber(int lineNumber){
		  this.lineNumber=lineNumber;
	}
	public int getLineNumber(){
		 return lineNumber;
	}
	public MyLineNumberReader(Reader r){
		super(r);
	}
	/*每次读取一行 LineNumber++  */
	public String readLine()throws IOException{
		lineNumber++;
		return super.myReadLine();
	}
}


setLineNumber();//设置行号开始
getLineNumber();//获取行号


字节输出流:
FileOutputStream
字符串变byte数组: "dadfda".getBytes();


字节读取流:
FileInputStream
available();//获取文件的大小


/*
字节流复制图片
*/
import java.io.*;
class Demo4 
{
	public static void main(String[] args) 
	{
		/*字节读取 输出流*/
		FileInputStream fis=null;
		FileOutputStream fos=null;
		try
		{
			fis=new FileInputStream("Dj.mp3");
			fos=new FileOutputStream("Dj_copy.mp3");
		
			//使用字节数组写入
			byte buf[]=new byte[1024];
			int len=0;
			while((len=fis.read(buf))!=-1){
				fos.write(buf,0,len);
			}
			
		}
		catch (IOException e)
		{
			System.out.println("复制图片失败");
		}
		finally
		{
			try
			{
				if(fis!=null)
					fis.close();
			}
			catch (IOException e)
			{
				System.out.println("复制文件失败");
			}
			try
			{
				if(fos!=null)
					fos.close();
			}
			catch (IOException e)
			{
				System.out.println("复制文件失败");
			}
		}
	}
}


/*
使用字节缓冲流 赋值图片
*/
import java.io.*;
class Demo5 
{
	public static void main(String[] args) 
	{
		/*字节缓冲区*/
		BufferedInputStream bis=null;
		BufferedOutputStream bos=null;
		try
		{
			bis=new BufferedInputStream(new FileInputStream("1.gif"));
			bos=new BufferedOutputStream(new FileOutputStream("1_copy.gif"));
			 /*使用字节数组读取数据*/
			 byte []buf=new byte[1024];
			 int len=0;
			 while((len=bis.read(buf))!=-1){
			 	 bos.write(buf,0,len);
			 }
		}
		catch (IOException e)
		{
			System.out.println("复制图片失败");
		}
		finally
		{
			try
			{
				if(bis!=null)
					bis.close();
			}
			catch (IOException e)
			{
				System.out.println("复制图片失败");
			}
			try
			{
				if(bos!=null)
					bos.close();
			}
			catch (IOException e)
			{
				System.out.println("复制图片失败");
			}
		}
	}
}


/*
  模拟BufferedInputStream自定义字节流缓冲区
*/
import java.io.*;
class Demo6
{
	public static void main(String[] args) 
	{
		MyBufferedInputStream mis=null;
		BufferedOutputStream bos=null;
		try
		{
			mis=new MyBufferedInputStream(new FileInputStream("Dj.mp3"));
			bos=new BufferedOutputStream(new FileOutputStream("Dj_copy.mp3"));
			/*单字节读取*/
			int b=0;
			while((b=mis.myRead())!=-1){
				 bos.write(b);
			}
		}
		catch (IOException e)
		{
			System.out.println("复制文件失败");
		}
		finally
		{
			try
			{
				if(mis!=null)
					mis.close();
			}
			catch (IOException e)
			{
				System.out.println("复制文件失败");
			}
				try
			{
				if(bos!=null)
					bos.close();
			}
			catch (IOException e)
			{
				System.out.println("复制文件失败");
			}
		}
	}
}
/*
自定义读取缓冲区
*/
class MyBufferedInputStream extends InputStream
{
	private InputStream i;
	private byte []buf=new byte[1024]; //存储数据
	private int count,pos;//读取个数,指针
	public MyBufferedInputStream(InputStream i){
		this.i=i;
	}
	public int myRead()throws IOException{
		if(count==0){ //如果字节数组读完重新获取数据
			count=i.read(buf);	 //获取读取个数
			if(count<0)//小于0 就是没有了
				return -1;
			pos=0;	   //每一次读取都把指针恢复到初始位置

			byte b=buf[pos++]; //每次读取的指针位置自增
			count--;	  //相对应的次数减少
			return b&0xff; //返回最低八位

		}else if(count>0){ //如果字节数组还没有读完继续读
		   byte b=buf[pos++];  //每次读取的指针位置自增
		   count--;	  //相对应的次数减少
		   return b&0xff; //返回最低八位
		}
		return -1;
	}
	public int read()throws IOException{
		return i.read();
	}
	public void close()throws IOException{
		 i.close();
	}
}



如何定义一个刚刚好的缓冲区不用循环呢?
byte []byte=new byte[字节读取流.available()];
不推荐这样使用,因为jvm默认启动是64m内存,就算可以设置启动内存,
但是过大的文件也是无法解决的,推荐使用new byte[1024]这样读取


能不能将字节流转成字符流,然后使用字符流的readLine方法呢?
InputStreamReader 是字节流通向字符流的桥梁
OutputStreamWriter 是字符流通向字节流的桥梁




流的操作基本规律:
痛苦的是流的对象很多,不知道该使用哪一个?
可以通过三个明确来完成:
1.明确源和目的
源:输入流 InputStream Reader
目的:输出流 OutputStream Writer
2.操作的数据是否是纯文本
是:字符流   Reader Writer
不是:字节流 InputStream OutputStream


3.当体系明确后,在明确要使用哪个具体对象,通过设备来分
源设备:内存,硬盘,键盘
目的设备:内存,硬盘,控制台


效率:是否需要提高效率?
是:使用字节流,或者字符流缓冲区.


扩展一下:是否需要指定编码表 ?
需要就要使用转换流 InputStreamReader OutputStreamWriter


/*

获取键盘输入 并存入到test.txt文件中
按照utf-8编码形式存取

1.明确源和设备
	源:键盘 System.in
	不是使用Reader么? System.in对应的不是字节流?
为了操作键盘的文本数据方便,转换成字符流操作最方便
所以这里使用InputStreamReader转换流,将字节流转换成字符流

	目的:硬盘文件  FileOutputStream();
2.是否是纯文本?
	是:Writer ,
3.是否需要提高xiaol
	是:使用BufferedReader BufferedWriter
4.是都需要指定编码表?
	是:使用OutputStreamWriter转换流,将字节流转换成字符流并指定编码


*/
import java.io.*;
class Demo7 
{
	public static void main(String[] args) 
	{
		BufferedReader br=null;
		BufferedWriter bw=null;
		try
		{
			//键盘录入
			br=new BufferedReader(new InputStreamReader(System.in));
			//输出到文本 ,按照utf-8编码形式
			bw=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("test.txt",true),"UTF-8"));
			String line=null;
			while((line=br.readLine())!=null){
				if("over".equals(line))
					return;
				bw.write(line);//写入			
				bw.flush();//每次都有刷新
				bw.newLine(); //换行
			}
		}
		catch (IOException e)
		{
			System.out.println("文件写入失败");
		}
		finally
		{
			try
			{
				if(br!=null)
					br.close();
			}
			catch (IOException e)
			{
				System.out.println("文件写入失败");
			}
			try
			{
				if(bw!=null)
					bw.close();
			}
			catch (IOException e)
			{
				System.out.println("文件写入失败");
			}
		}
	}
}



转换流什么时候使用?
字符流和字节流的桥梁,通常涉及到字符编码转换时,需要用到转换流


System类
改变标准输入输出设备
setIn();   //设置标准输入设备
setOut();  //设置标准输出设备


/*
System类设置标准输入 输出设备

setIn();
setOut();

缓冲区带行号的  复制文件打印 
*/
import java.io.*;
class Demo8 
{
	public static void main(String[] args) 
	{
		 LineNumberReader lr=null;
		 BufferedWriter bw=null;
		 try
		 {
			 //设置标准输入
			System.setIn(new FileInputStream("Demo1.java"));
			//设置标准输出
			System.setOut(new PrintStream("nima.java"));
			lr=new LineNumberReader(new InputStreamReader(System.in));
			bw=new BufferedWriter(new OutputStreamWriter(System.out));

			String line=null;
			while((line=lr.readLine())!=null){
				bw.write(lr.getLineNumber()+"\t"+line);
				bw.flush();
				bw.newLine();
			}
		 }
		 catch (IOException e)
		 {
			 System.out.println("读取失败");
		 }
		 finally
		 {
			try
			{
				if(lr!=null)
					lr.close();
			}
			catch (IOException e)
			 {
				 System.out.println("读取失败");
			 }
			 try
			{
				if(bw!=null)
					bw.close();
			}
			catch (IOException e)
			 {
				 System.out.println("读取失败");
			 }
		 }
	}
}



异常信息处理,输出到log文件
printStackTrack(字节流or字符流);  //输出异常信息


/*
打印异常信息到本地文件

  void printStackTrace() 
          将此 throwable 及其追踪输出至标准错误流。 
 void printStackTrace(PrintStream s) 
          将此 throwable 及其追踪输出到指定的输出流。 
 void printStackTrace(PrintWriter s) 
          将此 throwable 及其追踪输出到指定的 PrintWriter。 

*/
import java.text.SimpleDateFormat;
import java.util.Date;
import java.io.*;
class Demo10 
{
	public static void main(String[] args) throws IOException
	{
		Date d=new Date();
		SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
		String time=sdf.format(d);

		// void printStackTrace(PrintStream s) 
      //    将此 throwable 及其追踪输出到指定的输出流。
		int []arr={1,23,5};
	  try
	  {
		  System.out.println(arr[5]);
	  }
	  catch (Exception e)
	  {	  /*
		  //字节流
		  PrintStream ps=new PrintStream("exception.log");
		  ps.write(time.getBytes());
		  e.printStackTrace(ps);
		  */
		  //字符流
		  PrintWriter pw=new PrintWriter(new FileOutputStream("exception.log",true));
		  pw.write(time); 
		  e.printStackTrace(pw);
		   pw.flush();
	  }
		
	}
}



Properties

list(字节流或字符流); //输出系统信息列表


/*

打印Properties系统信息类

输出到文本properties.txt

 void list(PrintStream out) 
          将属性列表输出到指定的输出流。 
 void list(PrintWriter out) 
          将属性列表输出到指定的输出流。 


*/
import java.util.Properties;
import java.io.*;
class Demo9 
{
	public static void main(String[] args)throws IOException 
	{
		Properties p=System.getProperties();
			//字符流写出
			PrintWriter pw=new PrintWriter("list.txt");
			p.list(pw);
			pw.flush();//记得刷新

			//字节流写出
			//p.list(new PrintStream("list.txt"));
	}
}


 —————————— ASP.Net+Android+IOS开发.Net培训、期待与您交流!——————————

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值