JAVA API之IO流

本文深入讲解Java IO流的概念、分类及应用,包括字节流、字符流、缓冲流、对象流、数据流等,覆盖File操作、序列化、反序列化及字符集处理。

IO流

什么是流?

io流就是Java中运输数据的一种载体,它能够吧数据从一个地方运输到另一个地方
 
流的分类:
a.根据数据运输的方向划分:
  input输入 和 output输出
    所有的往内存中送数据都是输入
    所有的 往内存中出数据都是输出
b.根据传输数据的类型
  字节流
  字符流

File操作目录和文件信息

在这里插入图片描述

  • File的api
//构建File类对象
	File(String filePath);
	File(File parent,String child);
	File(String parentName,String child);
//判断是否是文件
	.isFile()
//判断是否是目录
	.isDirectory()
//获取文件的长度
	.length()
//判断文件或目录是否存在
	.exists()
//创建一个空文件,返回值boolean
//	如果指定的文件不存在,就创建文件返回true
//	如果指定的文件存在,就返回flase
	.createNewFile()	
//删除文件
//注意:
	//如果File表示一个目录
	//删除的时候,要保证目录必须是空的
	.delete()	
//创建目录
	.mkdir()
	
//创建多个目录
	.mkdirs()
	
//返回指定目录中的所有文件和目录
	.listFiles()	
	
//返回指定的目录中的部分文件和目录,用FileFileter设定筛选条件
	.listFiles()
//返回指定的目录中的部分文件和目录,用FilenameFileFileter设定筛选条件
	.listFile(FilenameFilter)	

字节流

字节流:可以从或向一个特定的方向读写数据,数据是字节
封装流/处理流:针对字节流进行封装,即对一个已经存在的流进行封装,通过所有的封装流能够对数据更有效的读写,封装流的底层还是字节流
通常字节流被称之为低级流
处理流被称之为高级流或过滤流

  • 低级流(InputStream/OutputStream)
InputStream   所有字节输入流的父类,其定义了基础的读取方法
	-int read()   抽象类
		读取一个字节,int的形式放回,int的第8位有效
		否则返回-1,表示文件末尾EOF end of file
	-int read(byte[] b)
		尝试最多读取给定数组length个字节,并存入该数组
		返回值为实际读取字节量的长度,否则返回-1,到文件末尾
	-int read(byte[] b , int offest , int len)
		将输入流中的最多len个数据字节,写入byte数组
		将从offset的位置开始写入数组,len不能超过数组的实际长度
		如果超过会报数组下边越界异常
	-void close()
		关闭此输入流并释放与该流关联的所有的系统资源
OutputStream  所有字节输出流的父类,其定义了基础的写出方法
	-void write(int d)写出整型数据的低8-void write(byte[] b)将给定的字节数组的数据全部写出
	-void write(byte[] b , int offest , int len)
		将给定的字节数组从偏移量offset开始的len个自己写入输出流
	-void flush()
		刷新此输出流并强制写出所有缓冲的输出字节
	-void close()
		关闭此输出流并释放与此输出流有关的所有的系统资源
  • 低级流-文件输出流(FileInputStream/FileOutputStream)
FileOutputStream:文件输输出流-可以操作文件内容-低级流-字节流
		//创建了一个输出流的对象,此对象跟硬盘的某个文件关联,对文件只能做输出操作
		OutputStream os = new FileOutputStream(new File("D://aa//fos.txt"));
		//把字符串转换成字节数组并写到os流对象中
		os.write("hello world!".getBytes());
		//清除缓冲,数据回写硬盘
		os.flush();
		//关闭流,并释放资源
		os.close();
FileInputStream:文件输入流-可以操作问价那内容-低级流-字节流
		//创建了一个输入流的对象,此对象跟硬盘的某个文件关联,对文件做输入操作
		InputStream is = new FileInputStream("d:/aa/fos.txt");
		int d = -1;
		while((d=is.read())!=-1){
			System.out.println((char)d);
		}
		is.close();
  • 高级流-缓冲流(ObjectInputStram/ObjectOutputStream)
缓冲流的原理:
	向硬件存储设备操作数据,导致增大跟硬件的交互次数,会降低读写的速度,做缓冲流的目的就是为了尽量减少跟硬件的交互次数
	缓冲是靠牺牲内存来提升io的读写效率
 BufferedOutputStream 缓冲输出流原理:
	缓冲输出流内部会维护一个缓冲区,每当我们向该流写出数据时,都会先将数据存入缓冲区,当缓冲区已满的时候,缓冲流会将数据一次性写出
		注意:
			void flush(),清除缓冲区,将缓冲区中的数据强制写出,以保证数据完整
	
BufferedInputStream 缓冲输入流原理:  
	缓冲输入流内部会维护一个缓冲区,每当我们向该流读入数据时,都会先将数据存入缓冲区,BufferedInputStream的read方法会从缓冲
	区读取数据,当缓冲区全部读取完毕,如果再次read的时候,会在一次把缓冲区填满,read在逐一从缓冲区读取数据,以此往复

	/**
	 * 用缓冲流的方式来复制文件
	 *  多字节 
	 * 1.已经减少了和硬盘的交互次数
	 * 2.人为自己做了一个缓冲,减少循环数
	 * @throws IOException
	 */
	@Test
	public void testMethod4() throws IOException {
		System.out.println("文件开始复制...");
		long begin = System.currentTimeMillis();
		// 构建输入低级流
		InputStream is = new FileInputStream("D:/aa/te du.zip");
		// 构建输入高级流
		BufferedInputStream bis = new BufferedInputStream(is);
		// 构建输出低级流
		OutputStream os = new FileOutputStream("D:/aa/tedu5.zip");
		// 构建输出高级流
		BufferedOutputStream bos = new BufferedOutputStream(os);

		// 多字节复制数据
		byte[] buf = new byte[1024 * 1024 * 4];
		int len = -1;
		while ((len = bis.read(buf)) != -1) {
			bos.write(buf, 0, len);
		}
		bis.close();
		is.close();
		bos.close();
		os.close();
		long end = System.currentTimeMillis();
		System.out.println("文件复制结束..." + (end - begin));
	}

  • 高级流-对象流(ObjectInputStram/ObjectOutputStream)
把内存的对象数据,序列化到硬盘上,也可以把硬盘上的文件反序列化回内存的对象

序列化: 
	把内存的对象序列化到硬盘上,以字节的方式体现
反序列化:
	把硬盘上的字节序列,反序列化回内存中的对象
	比如:
		Student stu = new Student("张三",20,"S001");
		stu-->硬盘(序列化)-->内存堆中出现stu对象(反序列化)
	
注意:
	如果要实现对象的序列化和反序列化,就必须对序列化的对象所对应的类实现java.io.Serializable接口
	且类中最好给一个long类型的序列化的版本号
	比如:
		public class Student implements Serializavle{
			private static final long serialVersionUID = 1L;
			fileld 属性
			method 方法
		}
java.io.Serializable接口:
	此接口仅表示可序列化语义,某个类实现这个接口,就是说这个类表示了可以序列化这个语义,这个类的子类也同样
	具备序列化语义,这个类需要提供一个常量SerializableUID用来表示本类的序列化版本号,如果想跨平台,就需要
	显示声明一个版本号,且平台两端的版本必须相同
	
	序列化类中可以有很多的属性,但部分属性不想被序列化和反序列化,把类中的不需要序列化的属性前加上transient修饰符
		transient:瞬间的,短暂的.临时的
		public class Student implements Serializable{
			private static final long serialVersionUID = 1L;		
			private transient String name; //不可以序列化
			private int age;//能序列化
			field  属性
			methd  方法
		}
比如:有一个student类实现了Serializable接口并添加了版本号
    属性:private String name;//可以序列化
		 private int age;//可以序列化
	  	 private transient String stuNo;//不可以序列化
	方法:有getter和setter还有toString

	//序列化对象到硬盘中
		Student stu1 = new Student();
		stu1.setName("张三");
		stu1.setAge(20);
		stu1.setStuNo("S001");
		//构建低级输出流
		OutputStream os = new FileOutputStream("d:/aa/student.data");
		//构建高级流,对象输出流
		ObjectOutputStream oos = new ObjectOutputStream(os);
		oos.writeObject(stu1);
		oos.flush();
		oos.close();
		os.close();
 // 反序列化操作
	try {
		//构建低级输入流
		InputStream is = new FileInputStream("d:/aa/student.data");
		//构建高级流 ,对象输入流
		ObjectInputStream ois = new ObjectInputStream(is);
		Student stu = (Student) ois.readObject();
		System.out.println(stu);
		ois.close();  
		is.close();
	} catch (Exception e) {
		e.printStackTrace();
	} 
		
  • 高级流-数据流(DataInputStream/DataOutputStream)
DataInputStream 数据输入流,适合对java基本数据类型的输入
	-构造函数
		DataInputStream(InputStream)	
	-readInt();
		类似的方法  readXXX(); XXX代表具体的某种类型
比如
	//构建低级流
	InputStream is = new FileInputStream("D:/aa/dos.txt");
	//构建高级流
	DataInputStream dis = new DataInputStream(is);
	int value = dis.readInt();
	String str = dis.readUTF();
	//输出顺序的类型要和文件存储位置的数据一致
	System.out.println(value+"    "+str);
	dis.close();
	is.close();
		
DataOutputStream 数据输出流,适合对java基本数据类型的输出
	-构造函数
		DataOutputStream(OutputStream)
	-writeInt();
		类似的方法  writeXXX(); XXX代表具体的某种类型
 比如:
	//构建低级流
	OutputStream os = new FileOutputStream("D:/aa/dos.txt");
	//构建高级流
	DataOutputStream dos = new DataOutputStream(os);
	dos.writeInt(1000);
	dos.writeUTF("Hello World!");
	dos.flush();
	dos.close();
	os.close();

字符流

字符流: 高级流之一
	针对字符流做低级流的两次或三次的封装处理,字符流也是高级流字符流的本质还是字节流
	
Reader  所有字符输入流的父类
	-是一个抽象类
	-常用api:
		-int read()
			读取一个字符,是占用整型数据的低16,低十六位有效
		-int read(char[] chars)
			读取一个字符数组的length个字符,并存储到字符数组中
			返回的实际读取的字符量
		-int read(char[] chars , int offset , int len)
			读取len个字符,存储到字符数组中,以offset位置为起点
writer  所有字符输出流的父类
	-是一个抽象类
	-常用api:
		-void write()
			写出一个字符
		-void write(char[] chars)
			写出一个字符数组
		-void write(char[] chars , int offset , int len)
			写数组,从offset开始写len个字符到字符数组
		
	-void write(String str);
		写出一个字符串
	-void write(String str , int offset , int len)
		写出字符串数据中的部分数据
  • 高级流-字符流(InputStreamReader/OutputStreamWriter)
InputStreamReader类: 字符输入流
	-可以设置字符集,
	-按照指定的字符集输入数据
	-将字节按照指定的字符集读入字符串数据
	-继承自Reader
	//字符输入流,多字符读取
	InputStream is = new FileInputStream("D:/aa/osw.txt");
	InputStreamReader isr = new InputStreamReader(is,"UTF-8");
	char[] chars = new char[13];
	int len = -1;
	while((len = isr.read(chars))!= -1){
		System.out.println(new String(chars).substring(0,len));
	}
	isr.close();
	is.close();
	
OutputStreamWriter类: 字符输出流
	-可以设置字符集,
	-按照指定的字符集输出数据
	-将字节按照指定的字符集写出字符串数据		
	-继承自Writer
	//将字节流转换成字符流
	OutputStream os = new FileOutputStream("D:/aa/osw.txt");
	OutputStreamWriter osw = new OutputStreamWriter(os,"UTF-8");
	osw.write("Hello World!,我们爱java");		
	osw.flush();
	osw.close();
	os.close();
  • 高级流-缓冲字符流(BufferedReader/BufferedWriter)
缓冲字符流:缓冲字符流自己维护一个缓冲字符数组
	
BufferedReader类:缓冲字符流输入
	-String readLine();//读取一行字符,读到末尾为null
BufferedWriter类:缓冲字符流输出
		//构建一个低级输入流
		InputStream is = new FileInputStream("D:/aa/dw.txt");
		//构建高级流 第二次封装
		Reader isr = new InputStreamReader(is);
		//第三层封装
		BufferedReader br = new BufferedReader(isr);
		char[] chars = new char[5];
		int len = -1;
		while((len = br.read(chars))!=-1){
			System.out.println(new String(chars).substring(0,len));
		}
		br.close();
		isr.close();
		is.close();
  • 特殊的类PrintWriter类
特殊的类,只有输出,没有输入
是具有自动行刷新的缓冲字符输出流
例如:
	OutputStream os = new FileOutputStream("D:/aa/pw.txt");
		Writer osw = new OutputStreamWriter(os,"UTF-8");
		PrintWriter pw = new PrintWriter(osw,true);//代表自动行刷新
		PrintWriter pw1 = new PrintWriter(osw);	
		pw.println("不是用write写出的,用println方法写的,是可以用write写的");
		pw.flush();
		pw.close();
		osw.close();
		os.close();
  • 总结

对于一些IO流的知识点的总结,前面还有一个RandomAccessFile随机读写类
这些常用的IO流需要记住,欢迎大家补充

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值