黑马程序员——IO流(中篇)

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

IO流是Java中很重要的内容,因此毕老师也花了很多时间讲解IO流,今天继续IO流的中篇:

1——  字符流缓冲区

缓冲区的出现提高了对数据的读写效率,创建缓冲区前,先有流对象
该缓冲区中提供了一个跨平台应用的的换行方法: newLine();
对应类:BufferedWriter  BufferedReader

先介绍字符流写入缓冲区 BufferedWriter,应用中分为三步

              1)创建一个字符写入对象;

              2)为了提高字符写入流效率,加入了缓冲技术;

              3)只要将需要被提高效率的流对象作为参数传递给缓冲区的构造函数即可

通过代码说明使用方法:

import java.io.*;
class  BufferedWriterDemo
{
	public static void main(String[] args) throws IOException 
	{
		 FileWriter fw = new FileWriter("buf.txt");//创建一个字符写入对象
		 //为了提高字符写入流效率,加入了缓冲技术
		 //只要将需要被提高效率的流对象作为参数传递给缓冲区的构造函数即可
		 
		 BufferedWriter bufw =new BufferedWriter(fw);
		 for (int x=1;x<5 ;x++ )
		 {
			 bufw.write("abc"+x);
			 bufw.newLine();  //换行符
			 bufw.flush(); //只要用到缓冲区就要刷新
		 }
		 bufw.close();  //关闭缓冲区就是在关闭缓冲区中的流对象
	}
}

字符读取流缓冲区    BufferedReader: 

该缓冲区提供了一个一次读一行的方法readline,方便于对文本数据的获取当返回null时,表示读到文件末尾.

import java.io.*;
class  BufferedReaderDemo
{
	public static void main(String[] args) throws IOException
	{
		 
		 //创建一个读取流对象和文件关联
		 FileReader fr=new FileReader("buf.txt");

		 //为了提高效率,加入缓冲技术,将字符读取流对象作为参数传递给缓冲对象的构造函数
		 BufferedReader bufr=new BufferedReader(fr);

		 String line=null;  //readLine()方法返回字符串
		 while ((line=bufr.readLine())!=null)
		 {
			 System.out.println(line);
		 }
		 bufr.close();
	}
}
根据 BufferedReader 类中readLine()方法的原理,自定义一个类中包含一个功能和readLine()一致的方法,模拟BufferedReader

import java.io.*;

class MyBufferedReader 
{
	private FileReader r;
	MyBufferedReader(FileReader r)
	{
		this.r=r;
	}
	
	//可以一次读一行数据的方法
	public String myReadLine() throws IOException
	{
		//定义一个临时容器,原BufferReader封装的事字符数组
		//为了演示方便,定义一个StringBuilder容器,因为最终还是要将数据转换成字符串
		StringBuilder sb = new StringBuilder();
		int ch=0;
		while ((ch=r.read())!=-1)  //文件的第一种读取方式,逐个字符读取,返回的是字符对应的ASC码
		{
			if(ch=='\r')  
				continue;
			if(ch=='\n')
				return sb.toString();  //遇见换行符,返回读到的内容,读一行结束
			else
				sb.append((char)ch);
		}
		if(sb.length()!=0)  //如果没读到换行符,但是读到的有内容,依然要返回读到的内容
			return sb.toString();

		return null; //没读到数据就返回空
	}

	public void myClose() throws IOException
	{
		r.close();
	}
	 
}


class MyBufferedReaderDemo
{
	public static void main(String[] args) throws IOException
	{
		 FileReader fr=new FileReader("buf.txt");
		 MyBufferedReader myBuf =new MyBufferedReader(fr);
		 String line=null;
		 while ((line=myBuf.myReadLine())!=null)
		 {
			 System.out.println(line);
		 }
		 myBuf.myClose();

	}
}

2  —— 装饰设计模式

装饰设计模式:当想要对已有对象进行功能增强时,可以定义类类,将已有对象传入,基于已有的功能,进行加强,自定义的该类称为装饰类。装饰类通常会通过构造方法接收被装饰的对象,基于被装饰的对象的功能,提供更强的功能。
----装饰模式和继承的区别和联系 :装饰模式是组合结构,
装饰模式比继承要灵活,避免了继承体系臃肿,而且降低了类与类之间的关系。
装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供更强功能,所以装饰类和被装饰类通常都属于一个体系中。

class Person  //原有类
{
	public void chifan()
	{
		System.out.println("吃饭");
	}
}

class SuperPerson  //装饰后的类
{
	private Person p;
	SuperPerson (Person p)
	{
		this.p=p;
	}
	public void superChifan()
	{
		System.out.println("开胃酒");
		p.chifan();
		System.out.println("甜点");

	}
}
class  PersonDemo
{
	public static void main(String[] args) 
	{
		Person p = new Person();  
		//p.chifan();

		SuperPerson sp=new SuperPerson(p); //装饰模式
		sp.superChifan();
	}
}

以下是一个装饰模式的小练习:

/*
自定义装饰模式:将指定文件文件带行号输出,
*/
import java.io.*;

class MyLineNumberReader
{
	private Reader r;//装Reader,流对象
	private int lineNumber;
	
	MyLineNumberReader(Reader r)
	{
		this.r=r;
	}
	public String myReadLine() throws IOException
	{
		lineNumber++;
		
		
		//定义一个临时容器,原BufferReader封装的事字符数组
		//为了演示方便,定义一个StringBuilder容器,因为最终还是要将数据转换成字符串
		StringBuilder sb = new StringBuilder();
		int ch=0;
		while ((ch=r.read())!=-1)  //文件的第一种读取方式,逐个字符读取,返回的是字符对应的ASC码
		{
			if(ch=='\r')  
				continue;
			if(ch=='\n')
				return sb.toString();  //遇见换行符,返回读到的内容,读一行结束
			else
				sb.append((char)ch);
		}
		if(sb.length()!=0)  //如果没读到换行符,但是读到的有内容,依然要返回读到的内容
			return sb.toString();

		return null; //没读到数据就返回空
	}

	public void setLineNumber(int lineNumber)
	{
		this.lineNumber = lineNumber;
	}

	public int getLineNumber()
	{
		return lineNumber;
	}

	public void myClose() throws IOException
	{
		r.close();
	}
}



class  MyLineNumberReaderDemo
{
	public static void main(String[] args) throws IOException
	{
		 FileReader fr= new FileReader("PersonDemo.java");
		 MyLineNumberReader mylnr = new MyLineNumberReader(fr);
		 String line = null;
		 while ((line=mylnr.myReadLine())!=null)
		 {
			 System.out.println(mylnr.getLineNumber()+"::"+line);
		 }
		 mylnr.myClose();
	}
}

3——字节流读取文件

字节流写文件的方法:OutputStream,   读文件的方法:InputStream,通过代码介绍两种方法的用法:


/*
InputStream OutputStream
字节流读写文件

*/
import java.io.*;

class  FileStream
{
	public static void main(String[] args)  throws IOException
	{
		
		writeFile();
		readFile_3();
	}
	//字节流读文件的三种方法,如果要读取数据偏大,容易内存溢出,不建议使用
	public static void readFile_3() throws IOException   
	{
		FileInputStream fis = new FileInputStream("fos.txt");
		byte[] buf=new byte[fis.available()];//定义一个大小刚好的缓冲区,不用再循环
		fis.read(buf);
		System.out.println(new String(buf));
		fis.close();

	}

	public static void readFile_2() throws IOException  //字节流读文件的第二种方法,数据读到数组中
	{
		FileInputStream fis = new FileInputStream("fos.txt");
		byte[] buf=new byte[1024]; 
		 int len =0;
		 while ((len=fis.read(buf))!=-1)
		 {
			 System.out.println(new String(buf,0,len));
		 }
		fis.close();
	}

	public static void readFile_1() throws IOException  //字节流读文件的第一种方法,逐个字符读取
	{
		FileInputStream fis = new FileInputStream("fos.txt");
		int ch=0;
		while ((ch=fis.read())!=-1)
		{
			System.out.println((char) ch);
		}
		fis.close();
	}

	public static void  writeFile() throws IOException  //字节流写文件不需要刷新
	{
		FileOutputStream fos = new FileOutputStream("fos.txt");
		fos.write("abcde".getBytes());//获取字节
		fos.close();
	}
}

字节流中同样有缓冲区,读取缓冲区:BufferedInputStream     写入缓冲区: BufferedOutputStream,下面是利用字节流缓冲区复制MP3文件到指定目录中方法:

/*
复制mp3文件,通过字节流缓冲区

*/
import java.io.*;
class  CopyMp3
{
	public static void main(String[] args) throws IOException
	{
		long start =System.currentTimeMillis();
		copy_1();
		long end=System.currentTimeMillis();
		System.out.println((end-start)+"毫秒");  //显示复制过程需要的时间
	}

	//通过字节流缓冲区完成复制
	public static void copy_1() throws IOException
	{
		BufferedInputStream bufis = new BufferedInputStream(new FileInputStream("c:\\0.mp3"));//硬盘中的文件读到缓冲区
		BufferedOutputStream bufos=new BufferedOutputStream(new FileOutputStream("c:\\1.mp3"));
		int by=0;
		while ((by=bufis.read())!=-1)  //逐个读缓冲区中数据
		{
			bufos.write(by); // 写到目的文件中
		}
		bufis.close();
		bufos.close();

	}
}

4——IO流输入和输出

System.out:对应的是标准输出设备,控制台,System.in:对应的标准输入设备,键盘。

 需求:
通过键盘录入数据,当录入一行数据后,将该行数据打印,如果录入的是over,停止录入。

import java.io.*;
class  ReadIn
{
	public static void main(String[] args) throws IOException
	{
		InputStream in=System.in;
		StringBuilder sb=new StringBuilder();

		while (true)
		{
			int ch=in.read();
			if(ch=='\r')
			continue;
			if (ch=='\n')  //判断输入是否是换行符
			{
				String s=sb.toString();
				if ("over".equals(s))
				 
					break;
				System.out.println(s.toUpperCase());//转换为大写输出
				sb.delete(0,sb.length());  //每录入一次,清空一次容器
				 			
			}
			else
				sb.append((char)ch);
		}
	 
	}
}

发现:键盘录入一行数据并打印其大写,其实就是Bufferedreader中读一行数据的原理,也就是readLine(),
readLine方法是字符流BuffererReader类中的方法,而键盘录入的read方法是字节流InputStream的方法,可以将字节流转成字符流后再使用readLine方法。将字节流对象转成字符流对象,使用转换流 InputStreamReader。同理也可以将字符流转换为字节流,使用OutputStreamWriter方法。下面使用转换流重新实现键盘输入的方法:

 
import java.io.*;
class  TransStreamDemo
{
	public static void main(String[] args)  throws IOException
	{
	/*	InputStream in=System.in; //获取键盘录入对象
		//将字节流对象转成字符流对象,使用转换流 InputStreamReader
		InputStreamReader isr= new InputStreamReader(in);
		//为了提高效率,使用字符窜缓冲区BufferedReader
		BufferedReader bufr = new BufferedReader(isr);  */

		//上面键盘录入的3句话可以简化为一句,也是键盘录入最常见写法:
		BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
		
	/*	OutputStream out=System.out;
		OutputStreamWriter osw=new OutputStreamWriter(out);
		BufferedWriter bufw=new BufferedWriter(osw);  */
		//以上三句话简化为一句为:
		BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(System.out));
	

		String line=null;
		while ((line=bufr.readLine())!=null)
		{
			if("over".equals(line))
				break;
			//System.out.println(line.toUpperCase());
			bufw.write(line.toUpperCase());
			bufw.newLine();  //换行
			bufw.flush();  //刷新

		} 
		bufr.close();
	}
}
流操作的基本规律:
应用中流对象往往有很多种,不知道用哪一个,通过三个明确来完成:
1.明确源和目的。
源:输入流,InputStream Reader        目的:输出流。OutputStream   Writer
2.操作的数据是否纯文本    ,是就用字符流,,不是用字节流
3.体系明确后,再明确要使用对象,通过设备区分。  源设备:内存,硬盘,键盘,目的设备:内存,硬盘,控制台。

转换流是字符和字节的桥梁

下面是转换流的应用:

import java.io.*;
class  TransStreamDemo2
{
	public static void main(String[] args) throws IOException
	{
		//BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));  //键盘录入
		BufferedReader bufr = new BufferedReader(new InputStreamReader(new FileInputStream("fos.txt")));  //指定文件输入

		// BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(System.out));  //控制台输出
		 BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("out.txt")));  // 输出:存储到指定文件中

		 String line=null;
		while ((line=bufr.readLine())!=null)
		{
			if("over".equals(line))
				break;
			//System.out.println(line.toUpperCase());
			bufw.write(line.toUpperCase());
			bufw.newLine();  //换行
			bufw.flush();  //刷新

		} 
		bufr.close();
	}
}
改变标准输入输出设备:

import java.io.*;
class  ChangeIO
{
	public static void main(String[] args) throws IOException
	{
		//BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));  //键盘录入
		 System.setIn(new FileInputStream("fos.java"));  //改变标准输入设备

		// BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(System.out));  //控制台输出
		 System.setOut(new PrintStream("12.txt"));  //改变标准输出设备
		 String line=null;
		while ((line=bufr.readLine())!=null)
		{
			if("over".equals(line))
				break;
			//System.out.println(line.toUpperCase());
			bufw.write(line.toUpperCase());
			bufw.newLine();  //换行
			bufw.flush();  //刷新

		} 
		bufr.close();
	}
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值