黑马程序员---IO流2(装饰设计模式,LineNumberReader,InputStream,OutputStream,InputStreamReader)

装饰设计模式:

当想要对已有的对象进行功能增强时,可以定义类,将已有的对象传入,基于以后的功能,并提供加强功能,那么自定义的这个类就称为装饰类。

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

例如:

  1: import java.io.*;
  2: 
  3: /*
  4: 使用装饰设计模式,比较灵活,降低了类与类之间的关系
  5: */
  6: class Person 
  7: {
  8: 	public void chifan()
  9: 	{
 10: 		System.out.println("吃饭");
 11: 	}
 12: }
 13: 
 14: class SuperPerson
 15: {
 16: 	private Person p;
 17: 
 18: 	//将Person类的对象通过SuperPerson的构造函数传进来,这样就可以在
 19: 	//SuperPerson类中使用Person对象的方法,并且可以对Person对象的功能进行增强
 20: 	SuperPerson(Person p)
 21: 	{
 22: 		this.p=p;
 23: 	}
 24: 
 25: 	public void superChifan()
 26: 	{
 27: 		System.out.println("开胃酒");
 28: 		p.chifan();
 29: 		System.out.println("甜点");
 30: 	}
 31: 
 32: }
 33: 
 34: class PersonDemo
 35: {
 36: 	public static void main(String[] args)
 37: 	{
 38: 		Person p=new Person();
 39: 		SuperPerson sp=new SuperPerson(p);
 40: 
 41: 		sp.superChifan();
 42: 	}
 43: }
 44: 
 45: 
 46: 
 47: 

MyReader  专门用来读取数据的类

      |MyBufferedTextReader

      |MyBufferedMediaReader

MyReader有很多子类,例如MyTextReader和MyMediaReader,但是单个读取的效率太低,因此又出现了使用缓冲区的子类,加强形式,但是这样MyReader每增加一个子类,就需要增加一个加强形式。这样扩展性太差。

如果想Buffer功能单独写成一个类呢,那么有

class  MyBufferReader

{

      MyBufferedReader(MyTextReader  mytext)  {   }

      MyBufferedReader(MyMediaReader mymedia)  {   }

      ………….

}

这样的话,MyReader每增加一个子类,MyBufferReader就要增加一个构造方法,扩展性也很差。那么找其参数的共同类型,改写成多态的形式,这样就提高了扩展性。

class   MyBufferedReader   extends  MyReader

{

         MyBufferReader(MyReader   r)  {    }

}

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

MyReader 专门用来读取数据的类

      |MyMediaReader

      |---MyBufferedReader


LineNumberReader:(BufferedReader的子类)

跟踪行号的缓冲字符输入流,此类定义了方法setLineNumber和getLineNumber,用于设置和获取当前行号。

  1: import java.io.*;
  2: 
  3: class MyLineNumberReader
  4: {
  5: 	private FileReader r;
  6: 	private int num=0;
  7: 	MyLineNumberReader(FileReader r)
  8: 	{
  9: 		this.r=r;
 10: 	}
 11: 
 12: 	public String myReadLine()throws IOException
 13: 	{
 14: 		num++;
 15: 		StringBuilder sb=new StringBuilder();
 16: 		int ch=0;
 17: 		while((ch=r.read())!=-1)
 18: 		{
 19: 			if(ch==‘\r‘)
 20: 				continue;
 21: 			if(ch==‘\n‘)
 22: 				return sb.toString();
 23: 			else sb.append((char)ch);
 24: 		}
 25: 
 26: 		if(sb.length()!=0)
 27: 			return sb.toString();
 28: 
 29: 		return null;
 30: 
 31: 	}
 32: 
 33: 	//设置行号
 34: 	public void mySetLineNumber(int num)
 35: 	{
 36: 		this.num=num;
 37: 	}
 38: 
 39: 	//获取行号
 40: 	public int myGetLineNumber()
 41: 	{
 42: 		return num;
 43: 	}
 44: 
 45: 	public void myClose()throws IOException
 46: 	{
 47: 		r.close();
 48: 	}
 49: 
 50: 
 51: }
 52: 
 53: 
 54: 
 55: 
 56: class MyLineNumberReaderDemo 
 57: {
 58: 	public static void main(String[] args) throws IOException
 59: 	{
 60: 		FileReader fr=new FileReader("MyBufferedReaderDemo.java");
 61: 		MyLineNumberReader mylnr=new MyLineNumberReader(fr);
 62: 
 63: 		String line=null;
 64: 		while((line=mylnr.myReadLine())!=null)
 65: 		{
 66: 			System.out.println(mylnr.myGetLineNumber()+":"+line);
 67: 		}
 68: 		mylnr.myClose();
 69: 
 70: 
 71: 	}
 72: }
 73: 


字节流:

需求,如果想要操作图片数据,这是需要使用到字节流。InputStream和OutputStream

  1: import java.io.*;
  2: 
  3: 
  4: class FileStream 
  5: {
  6: 	public static void writeFile()throws IOException
  7: 	{
  8: 		FileOutputStream fos=new FileOutputStream("fos.txt");
  9: 
 10: 		
 11: 		//字节流只可以写入字节或者字节数组,abcde为字符串,需要进行转换,getBytes()
 12: 		//getBytes()方法,将String编码为byte序列,并将结果存在一个新的byte数组中
 13: 		fos.write("abcde".getBytes());
 14: 
 15: 		//如果没有使用到指定的缓冲区,是不需要缓冲的,但是需要关闭资源
 16: 		fos.close();
 17: 	}
 18: 	
 19: 	//单个字节读取
 20: 	public static void readFile_1()throws IOException
 21: 	{
 22: 		FileInputStream fis=new FileInputStream("fos.txt");
 23: 
 24: 		int ch=0;
 25: 		while((ch=fis.read())!=-1)
 26: 		{
 27: 			System.out.println((char)ch);
 28: 		}
 29: 		fis.close();
 30: 	}
 31: 	
 32: 	//按字节数组来进行读取
 33: 	public static void readFile_2()throws IOException
 34: 	{
 35: 		FileInputStream fis=new FileInputStream("fos.txt");
 36: 
 37: 		byte[] buf=new byte[1024];
 38: 		int len=0;
 39: 
 40: 		while((len=fis.read(buf))!=-1)
 41: 		{
 42: 			System.out.println(new String(buf));
 43: 		}
 44: 
 45: 		fis.close();
 46: 	}
 47: 
 48: 	public static void readFile_3()throws IOException
 49: 	{
 50: 		FileInputStream fis=new FileInputStream("fos.txt");
 51: 
 52: 		//available()方法,返回值为文件中的字节数,包括换行符,这样可以定义一个刚好的缓冲区,不需要循环
 53: 
 54: 		byte[] buf=new byte[fis.available()];
 55: 
 56: 		fis.read(buf);
 57: 
 58: 		System.out.println(new String(buf));
 59: 
 60: 		fis.close();
 61: 	}
 62: 
 63: 		
 64: 
 65: 	public static void main(String[] args) throws IOException
 66: 	{
 67: 		readFile_3();
 68: 	}
 69: }
 70: 


练习:复制一张图片

  1: import java.io.*;
  2: 
  3: class PictureCopy 
  4: {
  5: 	public static void main(String[] args) 
  6: 	{
  7: 		FileInputStream fis=null;
  8: 		FileOutputStream fos=null;
  9: 		try
 10: 		{
 11: 			fis=new FileInputStream("IMG_0696.jpg");
 12: 			fos=new FileOutputStream("abc.jpg");
 13: 			byte[] buf=new byte[1024];
 14: 
 15: 			int len=0;
 16: 			while((len=fis.read(buf))!=-1)
 17: 			{
 18: 				fos.write(buf);
 19: 			}
 20: 			
 21: 		}
 22: 		catch (IOException e)
 23: 		{
 24: 		    System.out.println("...");
 25: 
 26: 		}
 27: 		finally
 28: 		{
 29: 			try
 30: 			{
 31: 				fis.close();
 32: 			}
 33: 			catch (IOException e)
 34: 			{
 35: 				System.out.println("关闭读取资源失败");
 36: 
 37: 			}
 38: 			try
 39: 			{
 40: 				fos.close();
 41: 			}
 42: 			catch (IOException e)
 43: 			{
 44: 				System.out.println("关闭写入资源失败");
 45: 
 46: 			}
 47: 		}
 48: 	}
 49: }
 50: 

MP3的复制,通过缓冲区:

  1: class CopyMP3 
  2: {
  3: 	public static void main(String[] args) throws IOException
  4: 	{
  5: 		//定义一个读取流对象,读取目标文件中的数据
  6: 		BufferedInputStream bufis=new BufferedInputStream(new FileInputStream("c:\\0.mp3"));
  7: 
  8: 		//定义一个输出流对象,用来将读取到的数据写入到目的文件中去
  9: 		BufferedOutputStream bufos=new BufferedOutputStream(new FileOutputStream("c:\\1.mp3"));
 10: 
 11: 		int by=0;
 12: 		byte[] buf=new byte[1024];
 13: 		while((by=bufis.read(buf))!=-1)
 14: 		{
 15: 			bufos.write(by);
 16: 		}
 17: 
 18: 		bufis.close();
 19: 		bufos.close();
 20: 
 21: 	}
 22: }
 23: 


自定义字节流缓冲区:

  1: class MyBufferedInputStream 
  2: {
  3: 	private InputStream in;
  4: 	//定义一个byte型的数组,用于存储数据
  5: 	private byte[] buf=new byte[1024];
  6: 	//count为计数器,pos为数组的指针
  7: 	private int pos=0,count=0;
  8: 
  9: 	MyBufferedInputStream(InputStream in)
 10: 	{
 11: 		this.in=in;
 12: 	}
 13: 
 14: 	//一次读取一字节,从
 15: 	public int myRead() throws IOException
 16: 	{
 17: 		//通过in来读取硬盘上的数据,并且存储到buf中
 18: 		if(count==0)
 19: 		{
 20: 			count=in.read(buf);
 21: 			if(count<0)
 22: 				return -1;
 23: 			pos=0;
 24: 			byte b=buf[pos];
 25: 			count--;
 26: 			pos++;
 27: 
 28: 			return b&255;
 29: 		}
 30: 		else if(count >0)
 31: 		{
 32: 			byte b=buf[pos];
 33: 			count--;
 34: 			pos++;
 35: 
 36: 			return b&255;
 37: 		}
 38: 		return -1;
 39: 	}
 40: 
 41: 	public void myClose()throws IOException
 42: 	{
 43: 		in.close();
 44: 	}
 45: 
 46: }
 47: 
 48: /*
 49: why b&255?
 50: 
 51: 若数据文件的第一个数据恰好是1111 1111
 52: 提升成了int类型以后,数据值为-1
 53: 
 54: 是-1的原因是因为在8个1前面补得为1,如果在前边补0,即可以保留原字节数据不变,又可以避免-1的出现
 55: 
 56: 1111 1111 1111 1111 1111 1111 1111 1111
 57: 0000 0000 0000 0000 0000 0000 1111 1111 
 58: 
 59: 
 60: 0000 0000 0000 0000 0000 0000 1111 1111 
 61: 提升为int型后,多占了内存,write方法写入时,将前面的舍弃,只保留后8位
 62: 
 63: */


读取键盘录入:

需求:通过键盘录入数据,当录入一行数据,就将该行数据进行打印,如果录入的数据为over,那么停止录入

  1: class InputStreamDemo 
  2: {
  3: 	public static void main(String[] args) 
  4: 	{
  5: 		InputStream in=System.in;
  6: 		StringBuilder sb=new StringBuilder();
  7: 		while(true)
  8: 		{
  9: 			int ch=in.read();
 10: 			if(ch==‘\r‘)
 11: 				continue;
 12: 			if(ch==‘\n‘)
 13: 			{
 14: 				String s=sb.toString();
 15: 				if("over".equals(s))
 16: 					break;
 17: 				System.out.println(s.toUpperCase());
 18: 				//每次录入一行数据,就将该行数据进行打印以后,应该将存在StringBuilder里面的
 19: 				//内容清空,下次录入时,才不会有下一次的数据
 20: 
 21: 				sb.delete(0,sb.length());
 22: 
 23: 			}
 24: 			else sb.append((char)ch);
 25: 		}
 26: 	}
 27: }
 28: 
 29: /*
 30: 以上代码即为读一行数据的原理,即readLine()方法
 31: 那能不能直接用readLine方法来完成键盘录入的一行数据的读取呢?
 32: 
 33: 但是readLine方法是字符流BufferedReader类中的方法,而键盘录入的read方法,是字节流InputStream的方法
 34: 那么能不能将字节流转换成字符流,而使用字符流缓冲区的readLine方法呢?
 35: 
 36: 使用InputStreamReader类
 37: 
 38: */
  1: public void method()throws Exception
  2: 	{
  3: 		InputStream in=System.in;
  4: 
  5: 		//将字节流对象转成字符流对象,使用转换流
  6: 		InputStreamReader isr=new InputStreamReader(in);
  7: 		//为了提高效率,将字符串进行缓冲区技术高效操作,使用BufferedReader
  8: 		BufferedReader bufr=new BufferedReader(isr);
  9: 
 10: 		String line=null;
 11: 		while((line=bufr.readLine())!=null)
 12: 		{
 13: 			if("over".equals(line))
 14: 				break;
 15: 			System.out.println(line.toUpperCase());
 16: 		}
 17: 
 18: 		bufr.close();
 19: 	}

黑马程序员---IO流2(装饰设计模式,LineNumberReader,InputStream,OutputStream,InputStreamReader)

上一篇:CAP的相对论(下)


下一篇:OceanBase Docker 体验