一,IO流的概述
1.1 什么是IO流
我们把数据的传输,看成是一种数据的流动,按照指定的流向进行输出的输入和输出。以内存为基准。
1.2 IO流的分类
根据数据的流向划分:输入流 和 输出流
输入流:把数据从其他设备上读取到内存中
输出流:把数据从内存中写到其他设备上
根据数据的类型划分:字节流 和 字符流
字节流:以字节为单位,任何文件都可以使用字节流进行读写
字符流:以字符为单位,一般只能对文本进行读写
1.3 IO流的顶层父类
字节输入流:InputStream
字节输出流:OutputStream
字符输入流:Reader
字符输出流:Writer
注:
- 它们及其子类们都在 java.io 包中
- 它们都是 抽象类
二,FileOutputStream 文件字节输出流
2.1 概述
概述:该类是 OutputStream 的一个专门针对文件进行写出的流,它定义了一系列与写出相关的方法。
2.2 构造函数
- new FileOutputStream(File f):根据指定文件对象所指向的文件路径创建文件字节输出流对象
- new FileOutputStream(String name):根据指定文件路径创建文件字节输出流对象
- new FileOutputStream(File f,boolean b):功能同上,第二个参数值为 true 时,表示该文件可以续写
- new FileOutputStream(String name,boolean b):功能同上,第二个参数值为 true 时,表示该文件可以续写
2.3 常用方法
- close():释放资源,如果执行了 close() 方法,那么就不能在写入了
- flush():刷新缓冲区
- write(int ch):根据十进制数写入对应的字符
- writer(byte[] b):写入指定的字节数组,如果要写入字符串,可以通过,字符串的 getBytes() 方法获取对应的字节数组
- writer(byte[] b,int index ,int lenth):从字节数组中的指定位置获取指定数量的元素写入到文件中
注:
- 如果想要续写,需要使用带有 boolean 参数的构造函数来创建对象,并且布尔值必须是 true
- 关于输出换行:
- windows:\r\n
- unix:\n
- mac:\r
- 流用完后一定要关闭
三,FileInputStream 文件字节输入流
3.1概述
概述:该类是 InputStream 的一个专门针对文件进行读取的流,它定义了一系列与读取相关的方法。
3.2 构造函数
- new FileInputStream(File f):根据指定文件对象所指向的文件路径创建文件字节输入流对象
- new FileInputStream(String name):根据指定文件路径创建文件字节输入流对象
3.3 常用方法
- read():读取单个字符所对应的十进制数,返回 -1 表示读完了
FileInputStream fis = new FileInputStream("E:\\资料\\demo\\t1.txt"); int ch = 0; while((ch = fis.read()) != -1){ System.out.println((char)ch); }
- read(byte b[],int a,int b):从指定文件中的a位置开始,读取b个字符,存储到数组中
- read(byte b[]):从指定文件中读取还未获取到的字符,存储到数组中,返回读取到的有效个数
StringBuilder sb = new StringBuilder(); int len = 0; while((len = fis.read(b)) != -1){ sb.append(new String(b,0,len)); } System.out.println(sb);
- close():释放资源
练习:将 D 盘中的图片,复制到 E 盘中
FileInputStream fis = new FileInputStream("C:\\Users\\qianfeng\\Desktop\\a.png"); FileOutputStream fos = new FileOutputStream("E:\\b.png"); byte[] b = new byte[1024]; int len = 0; while((len = fis.read(b)) != -1){ fos.write(b,0,len); } fis.close(); fos.close();
注:流关闭的原则是“先开后管”
四,FileReader 文件字符输入流
4.1 概述
概述:该类是 Reader 的一个专门针对文件进行读取的流,它定义了一系列与读取相关的方法。
4.2 构造函数
- new FileReader(File f)
- new FileReader(String name)
4.3 常用方法
- read()
- read(char ch[])
- read(char ch[] ,int index,int lenth)
- close()
五,FileWriter 文件字符输出流
5.1 概念
概述:该类是 Writer 的一个专门针对文件进行写出的流,它定义了一系列与写出相关的方法。
5.2 构造函数
- new FileWriter(File f)
- new FileWriter(String name)
- new FileWriter(File f,boolean b)
- new FileWriter(String name,boolean b)
5.3 常用方法
- close():释放资源,执行释放动作前,会先将缓冲区中的数据刷新到的目标位置
- flush():当使用 write() 方法写入文件时,只是把数据写入到了缓冲区中,需要用 flush() 才能将数据从缓冲区中真正的刷新到目标位置
- write(int ch)
- write(String str)
- write(String str,int index,int length)
- write(char[] ch)
- write(char[] ch,int index,int length)
close() 与 flush() 的区别:
flush() :只是将数据从缓冲区中刷新到目标位置,刷新后,该输出流仍能正常使用
close():会先将缓冲区中的数据刷新到的目标位置,再关闭资源,关闭后,该流不能再使用
六,属性集 Properties
6.1 概念
概念:Properties 是 HashTable 的一个子类,它用来表示持久的属性集,它使用键值对的方式存储数据。
注:
- Properties 一般用于读取配置文件
- Properties 中的键值对都是字符串类型的
6.2 构造函数
- new Properties()
6.3 常用方法
- setProperties(String key,String value)
- getProperties(String key)
- stringPropertyName():返回当前 Properties 所有键组成的 Set 集合
6.4 Properties 与流相关的操作
方法:
- void load(InputStream):从字节输入流中读取键值对,使用 Properties 加载流对象
- void load(Reader):从字符输入流中读取键值对,使用 Properties 加载流对象
// InputStream is = new FileInputStream("xxx"); // 绝对路径 // InputStream is = new FileInputStream("src\\jdbc.properties"); // Reader is = new FileReader("E:\\workspace\\day26_02_流\\src\\jdbc.properties"); Reader is = new FileReader("src\\jdbc.properties"); prop.load(is); System.out.println(prop.getProperty("username")); System.out.println(prop.getProperty("password"));
七,缓冲流
7.1 概念
概念:缓冲流,也称为高效流,它是对4个基本的 FileXxx 流的增强
分类:
- 字节缓冲流:BufferedInputStream 字节缓冲输入流,BufferedOutputStream 字节缓冲输出流
- 字符缓冲流:BufferedReader 字符缓冲输入流,BufferedWriter 字符缓冲输出流
缓冲流的原理:在创建流对象的同时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区的读写,减少IO操作的次数,从而提高读写效率。
7.2 构造函数
- BufferedReader br = new BufferedReader(Reader r)
- BufferedWriter bw = new BufferedWriter(Writer w)
- BufferedInputStream bis = new BufferedInputStream(InputStream is)
- BufferedOutputStream bos = new BufferedOutputStream(OutputStream os)
普通流和缓冲流的效率比较:
// 文件字节输入输出流 public static void f1() throws Exception{ FileInputStream fis = new FileInputStream("E:\\eclipse\\eclipse-jee-neon-R-win32-x86_64.zip"); FileOutputStream fos = new FileOutputStream("C:\\Users\\qianfeng\\Desktop\\片子\\e.zip"); int len = 0; byte[] b = new byte[1024]; while((len = fis.read(b)) != -1){ fos.write(b,0,len); } fos.close(); fis.close(); } // 缓冲字节输入输出流 public static void f2() throws Exception{ FileInputStream fis = new FileInputStream("E:\\eclipse\\eclipse-jee-neon-R-win32-x86_64.zip"); BufferedInputStream bis = new BufferedInputStream(fis); FileOutputStream fos = new FileOutputStream("C:\\Users\\qianfeng\\Desktop\\片子\\e.zip"); BufferedOutputStream bos = new BufferedOutputStream(fos); int len = 0; byte[] b = new byte[1024]; while((len = bis.read(b)) != -1){ bos.write(b,0,len); } bos.close(); fos.close(); bis.close(); fis.close(); }
7.3 常用方法
缓冲流中的方法与普通流中的方法基本相同
特有方法:
- BufferedReader 中的 readLine():读取一整行
- BufferedWriter 中的 newLine():表示换行,自动适配当前操作系统
7.4 练习
4.低头思故乡。 2.疑似地上霜。 1.床前明月光, 3.举头望明月, // 将其按照1234排序,输出到指定文件中
方法一:
public class Test1 { public static void main(String[] args) throws Exception { BufferedReader br = new BufferedReader(new FileReader("C:\\Users\\qianfeng\\Desktop\\练习.txt")); BufferedWriter bw = new BufferedWriter(new FileWriter("C:\\Users\\qianfeng\\Desktop\\show.txt")); HashMap<String, String> map = new HashMap<>(); String str = null; while((str = br.readLine()) != null){ String s[] = str.split("[.]"); map.put(s[0], s[1]); } for(int i = 1;i <= map.size() ;i++){ String key = i + ""; String value = map.get(key); String s = key + "." + value; bw.write(s); bw.newLine(); } bw.close(); br.close(); } }
方法二:
public class Test2 { public static void main(String[] args) throws Exception{ BufferedReader br = new BufferedReader(new FileReader("C:\\Users\\qianfeng\\Desktop\\练习.txt")); BufferedWriter bw = new BufferedWriter(new FileWriter("C:\\Users\\qianfeng\\Desktop\\show.txt")); ArrayList<QueryVo> vos = new ArrayList<>(); String str = null; while((str = br.readLine()) != null){ String[] s = str.split("\\."); QueryVo vo = new QueryVo(); vo.num = s[0]; vo.msg = s[1]; vos.add(vo); } System.out.println(vos); Collections.sort(vos); System.out.println(vos); for (QueryVo vo : vos) { String num = vo.num; String msg = vo.msg; String s = num + "."+msg; bw.write(s); bw.newLine(); } bw.close(); } } class QueryVo implements Comparable<QueryVo>{ String num; String msg; @Override public int compareTo(QueryVo o) { // return this.num.compareTo(o.num); return Integer.valueOf(this.num) - Integer.valueOf(o.num); } }
八,转换流
8.1 字符编码和字符集
字符编码:在屏幕上看到的任何字符在计算机底层都是以某种规则转换成二进制的形式出现的,这种转换方式就叫做编码;将计算机底层的二进制数以某种规则显示在屏幕上的这种转换方式就叫做解码。如果转换规则错误,或者转换的规则不匹配就会发生乱码。
简单的说字符编码就是一套字符与二进制数转换的规则
字符集:也叫做编码表,它是系统支持的所有字符的一个集合,包含各个国家文字、标点符号、图形符号。
ASCII:它是基于拉丁字母的一套计算机编码系统,共有128个字符
ISO8859-1:拉丁码表,不包含中文
GB2312:GB是国标的意思,简体中文码表
GBK:最常用的中文码表,是在GB2312上的扩展,windows 操作系统的默认编码格式就是GBK
Unicode:万国码,满足跨语言、跨平台进行文本转换、处理的要求。
UTF-8:它可以用来表示Unicode标准中的任何字符,它逐渐成为电子邮箱、网页及其他存储或传送文字的应用中,优先采用的编码。
2.2 InputStreamReader
2.2.1 概述
概念:它是 Reader 的子类,它是从字节流转换到字符流的桥梁,它读取字节,并使用指定的字符集将其转换成字符。
2.2.2 构造函数
- new InputStreamReader(InputStream in)
- new InputStreamReader(InputStream in,String charset)
2.3 OutputStreamWriter
2.3.1 概述
概述:它是 Writer 的子类,它的从字符流转换到字节流的桥梁,它读取字符,并使用指定的字符集将字符转换成字节。
2.3.2 构造函数
- new OutputStreamWriter(OutputStream os)
- new OutputStreamWriter(OutputStream os,String charset)
2.4 代码
FileInputStream fis = new FileInputStream("C:\\Users\\qianfeng\\Desktop\\test.txt"); InputStreamReader isr = new InputStreamReader(fis,"utf-8"); int ch = 0; while((ch = isr.read()) != -1){ System.out.println((char)ch); } isr.close(); System.out.println("------------------------------"); FileOutputStream fos = new FileOutputStream("C:\\Users\\qianfeng\\Desktop\\demo.txt"); OutputStreamWriter osw = new OutputStreamWriter(fos, "utf-8"); osw.write("你好"); osw.close();
九,对象流 (序列化流)
9.1 序列化
Java 中提供了一种对象的序列化机制,允许将一个对象及其属性持久化的存储到文件中。
序列化:将对象存储到文件中
反序列化,将文件中的对象解析出来
9.2 ObjectOutputStream
构造方法:new ObjectOutputStream(OutputStream out)
注:
- 一个类中的对象要想序列化,该类必须实现 Serializable 接口,这个接口是一个标记接口,不实现此接口的类不能序列化和反序列化,会发生 NotSerializable Exception。
- 如果不想让某个属性被序列化,可以使用 transient 关键字修饰。
Person p = new Person(); p.name = "乔碧萝"; p.age = 25; p.sex = "男"; ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:\\Users\\qianfeng\\Desktop\\demo.txt")); oos.writeObject(p); // 写入对象的核心方法 oos.close();
9.2 ObjectInputStream
构造方法:new ObjectInputStream(InputStream out)
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:\\Users\\qianfeng\\Desktop\\demo.txt")); Person pp = (Person)ois.readObject(); // 读取对象的核心方法 System.out.println(pp.name); System.out.println(pp.age); System.out.println(pp.sex);