Java基础学习笔记——IO(1)

本文深入讲解Java中的IO流概念,包括字节流与字符流的区别,标准IO流处理,异常处理,以及装饰设计模式的应用。详细介绍了FileWriter、FileReader、BufferedWriter和BufferedReader的使用方法,并通过实例演示了如何复制图片文件。

概述

  1. IO处理的对象其实就是内存与外围设备(硬盘,U盘,打印机等),分为两大类:输入流(从硬盘到内存),输出流(从内存到硬盘)
  2. 字节流:处理所有数据。
  3. 字符流:只能处理字符,之所以有字符流,是因为存在GBK、Unicode等不同的码表,相同的字节根据不同的码表解析出的文字不一样,于是便将码表与字节流进行了封装,产生了字符流。(读取文字字节数据后,先查编码表,获取对应的文字,再对文字进行操作)

体系结构

一般来说,子类名的后缀是父类名,子类名的前缀表示子类的功能。

字符流

顶层父类:Reader、Writer

FileWriter(字符输出流)

		FileWriter fw=new FileWriter(".\\demo02.txt",true);
//		new对象之后,便创建了相应的文件与流对象,默认根目录为项目目录(与src同级别),而不是此java文件目录
//		没有则创建,有,第二个参数为true续写,第二个参数为false覆盖
		fw.write("haha");
//		内存中写入,未保存
		fw.flush();
//		表示保存,防止断电后数据在内存中丢失
		fw.close();
//		表示保存并退出,关闭流对象
标准的IO流处理异常
  1. try 外面声明 fw=null
  2. try 内部为fw赋值对象
  3. finally 写fw.close语句,本身还需要再围绕try catch 以防止关闭异常
  4. finally 在写fw.close之前,需要判断是否fw==null以防止之前的try没有读到文件,报空指针异常,这样的话根本就没有流可以关闭。

FileReader(字符输入流)

  1. 使用read()方法读取单个字符,返回数字。
  2. 文件在存入的时候,肯定会有首部标识和尾部标识,使用read()方法的时候,是肯定要读取到末尾的,如果读到了末尾标识,将返回-1(这里其实是走了底层)
使用char[] buffer读取示例(自制缓冲区)
        FileReader fr=new FileReader("demo02.txt");
		char[] buf=new char[1024];
		//一般大小为1024
		int len;
		while((len=fr.read(buf))!=-1) {
			System.out.println(new String(buf,0,len));
		}

要注意为什么不直接打印buffer,之前存在buffer的数据,在buffer重新读取的时候不会自动清空,毕竟在堆内存只有一个buffer,java没有义务在每次读取的时候先把这个buffer里面的内容清空,如果读到了就覆盖,如果没读到就不覆盖还是以前的东西,我们只能通过返回值来判断读到哪个地方的数据是新旧数据分界线。

字符流缓冲区(java提供的缓冲区)

缓冲区其实主要目的是对两个不同的流进行关联(比如将一个文件内容复制到另一个文件,需要两个流,而缓冲区便是对这两个流进行关联的)
缓冲区的出现其实大大省去的频繁的new,提高了性能。缓冲区仅仅起到了提高效率的作用,没有调用底层。关闭缓冲区本质上其实是关上了流。

BufferedWriter
        FileWriter fr=new FileWriter("demo03.txt");
        BufferedWriter bufr=new BufferedWriter(fr);
        bufr.write("hahaaxiefafe");
        bufr.newLine();
        //newLine()缓冲区特有
        bufr.write("hahaaxiefafe");
        bufr.flush();
        bufr.close();

其实将流对象赋给构造函数后,以后对流的各种处理直接操作这个缓冲区就行了。

BufferedReader

BufferedReader是读的缓冲区,还提供了特有的readLine()方法。注意返回的数据不包含换行符!!!

		FileReader fr=new FileReader("demo03.txt");
		BufferedReader bufr=new BufferedReader(fr);
		String line=null;
		while((line=bufr.readLine())!=null) {
			System.out.println(line);
			//注意readline()返回的每一行不包含换行符号!
		}
		bufr.close();

字节流

  1. 顶层父类:InputStream、OutputStream
  2. 缓冲区:缓冲区使用的数组是byte[] 而不是char[] 因为最小单位和字符流不一样
  3. 注意一点:写数据的时候不需要临时缓冲,因为不需要像字符流那样编码解码!所以直接write()方法之后就会在目的地写文件了。FileOutputStream的flush()方法其实内部根本啥都不做!当然close()还是有意义的。
  4. fis.available()返回文件大小(字节表示)

举例——复制图片文件

  1. 自己设计buffer
		FileOutputStream fos=new FileOutputStream("bat.jpg");
		FileInputStream fis=new FileInputStream("batman.jpg");
		byte[] buf=new byte[1024];
		int len=0;
		while((len=fis.read(buf))!=-1){
			fos.write(buf,0,len);
		}
		fos.close();
		fis.close();
  1. 使用提供的buffer
		FileOutputStream fos=new FileOutputStream("bat.jpg");
		FileInputStream fis=new FileInputStream("batman.jpg");
		BufferedOutputStream bufo=new BufferedOutputStream(fos);
		BufferedInputStream bufi=new BufferedInputStream(fis);
		
		int len=0;
		while((len=bufi.read())!=-1){
			bufo.write(len);
		}
		bufo.close();
		bufi.close();

注意如果不用buffer,使用上面读一个字节写一个字节的方式效率会非常慢!!!

装饰设计模式

描述

当对一组对象的功能进行增强的时候,就可以使用该模式进行问题的解决。其实IO里的buffer就是使用装饰设计模式。

装饰和继承都能实现一样的特点:对功能扩展增强。

解释原因:只是为了扩展功能而进行继承会使得体系越来越臃肿,所以会有装饰设计模式,可以这样比喻:我们有一堆相同的对象,谁需要扩展功能,那就把它給穿上一层“铠甲”(放入装饰类的构造函数),让它自己有扩展功能就好了。其它的对象不需要穿铠甲的,就不需要了。这样与继承相比,无疑是简单明了的,如果都继承的话,我这个实例即使不想扩展功能也不行,因为我继承了之后就“天赋异禀”了,这个能力与生俱来,穿铠甲就没有任何意义了。身边都是一群一样天赋的人,我的优越性又有何在呢。

拿BufferWriter举例子,这就是铠甲,穿上这层铠甲的Writer写效率会大大增强!不穿的就效率低。

代码示例

public class NewPerson {
	private Person p;
	public NewPerson(Person p) {
		this.p=p;
	}
	public void eat() {
		System.out.println("have a couple of tea");
		p.eat();
		System.out.println("have some wines");
	}

}

注意

装饰类和被装饰类必须同属于一个接口或者父类。即:铠甲与穿铠甲的骑士同属于一个父亲。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值