缓冲流、转换流、序列化流

缓冲流

概述

缓冲流,也叫高效流,是对4个基本的FileXxx流的增强,所以也是4个流,按照数据类型分类:

  • 字节缓冲流BufferedInputStream,BufferedOutputStrea
  • 字符缓冲流BufferedReader,BufferedWriter

缓冲流的基本原理,是在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲去读写,减少系统IO次数,从而提高读写的效率

缓冲流原理

字节缓冲流

构造方法

public BufferedInputStream(InputStream in):创建一个新的缓冲输入流

public BufferedOutputStream(OutputStream out):创建一个新的缓冲输入流

字节缓冲输入流

import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;/*java.io.BufferedOutputStream extends OutputStreamBufferedOutputStream:字节缓冲输出流继承自父类的共性成员方法:- public void close(): 关闭此输出流并释放与此流相关联的任何系统资源- public void flush(): 刷新此输出流并强制任何缓冲的输出字节被写出。- public void write(byte[]b):将b.length字节从指定的字节数组写入此输出流。- public void write(byte[]b, int off, intlen):从指定的字节数组写入len字节,从偏移量off开始输出到此输出流。- public abstract void write(int b) :将指定的字节输出流构造方法:BufferedOutputStream(OutputStream out) 创建一个新的缓冲输出流,以将数据写入指定的底层输出流。BufferedOutputStream(OutputStream out, int size) 创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输出流。参数:OutputStream out:字节输出流我们可以传递FileOutputStream,缓冲流会给FileOutputStream增加一个缓冲区,提高FileOutputStream的写入效率int size:指定缓冲流内部缓冲区的大小,不指定默认使用步骤(重点):1.创建FileOutputStream对象,构造方法中绑定要输出的目的地2.创建BufferedOutputStream对象,构造方法中传递FileOutputStream对象,提高FileOutputStream对象效率3.使用BufferedOutputStream对象中的方法write,把数据写入到内部缓冲区中4.使用BufferedOutputStream对象中的方法flush,把内部缓冲去的数据,刷新到文件中5.释放资源(会先调用flush方法刷新数据,第4步可以省略)*/
public class Demo01BufferedOutputStream {public static void main(String[] args) throws IOException {//1.创建FileOutputStream对象,构造方法中绑定要输出的目的地FileOutputStream fos = new FileOutputStream("D:\\IDEA2019(中文版)\\ZXL\\src\\com\\company\\pratise\\IOAndProperties\\a.txt");//2.创建BufferedOutputStream对象,构造方法中传递FileOutputStream对象,提高FileOutputStream对象效率BufferedOutputStream bos = new BufferedOutputStream(fos);//3.使用BufferedOutputStream对象中的方法write,把数据写入到内部缓冲区中bos.write("我把数据写入到内部缓冲区中".getBytes());//4.使用BufferedOutputStream对象中的方法flush,把内部缓冲去的数据,刷新到文件中bos.flush();//5.释放资源(会先调用flush方法刷新数据,第4步可以省略)bos.close();}
}

字节缓冲输出流

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;/*java.io.BufferedInputStream extends InputStreamBufferedInputStream:字节缓冲输入流继承自父类的成员方法:abstract  int read() 从输入流中读取数据的下一个字节。int read(byte[] b) 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。void close() 关闭此输入流并释放与该流关联的所有系统资源。构造方法:BufferedInputStream(InputStream in) 创建一个 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。BufferedInputStream(InputStream in, int size) 创建具有指定缓冲区大小的 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。参数:InputStream in:字节输入流我们可以传递FileInputStream,缓冲流会出FileInputStream增加一个缓冲区,提高FileInputStream的读取效率int size:指定缓冲流内部缓冲区的大小,不指定默认使用步骤(重点):1.创建FileInputStream对象,构造方法中绑定要读取的数据源2.创建BufferedInputStream对象,构造方法中传递FileInputStream对象,提高FileInputStream对象的读取效率3.使用BufferedInputStream对象中的方法read,读取文件4.释放资源*/
public class Demo02BufferInputStream {public static void main(String[] args) throws IOException {//1.创建FileInputStream对象,构造方法中绑定要读取的数据源FileInputStream fis = new FileInputStream("D:\\IDEA2019(中文版)\\ZXL\\src\\com\\company\\pratise\\IO\\IO_BufferedStream\\a.txt");//2.创建BufferedInputStream对象,构造方法中传递FileInputStream对象,提高FileInputStream对象的读取效率BufferedInputStream bis = new BufferedInputStream(fis);//3.使用BufferedInputStream对象中的方法read,读取文件//int read() 从输入流中读取数据的下一个字节/*int len = 0;//记录每次读取到的字节while ((len = bis.read()) != -1) {System.out.println(len);}*///int read(byte[] b) 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中byte[] bytes = new byte[1024];//存储每次读取的数据int len = 0;//记录每次读取的有效字节数while ((len = bis.read(bytes)) != -1) {System.out.println(new String(bytes,0,len));}//释放资源bis.close();}
}

效率测试

import java.io.*;/*文件复制练习:一读一写明确:数据源:c:\\1.jpg数据的目的地:d:\\1.jpg文件的复制步骤:1.创建字节缓冲输入流对象,构造方法中传递字节输入流2.创建字节缓冲输出流对象,构造方法中传递字节输出流3.使用字节缓冲输入流对象中的方法read,读取文件4.使用字节缓冲输出流对象中的方法write,把读取的数据写入到内部缓冲区5.释放资源(会先把缓冲切的数据,刷新到文件中)*/
public class Demo02CopyFile {public static void main(String[] args) throws IOException {long s = System.currentTimeMillis();//1.创建字节缓冲输入流对象,构造方法中传递字节输入流BufferedInputStream bis = new BufferedInputStream(new FileInputStream("d:\\1.png"));//2.创建字节缓冲输出流对象,构造方法中传递字节输出流BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("f:\\1.png"));//3.使用字节缓冲输入流对象中的方法read,读取文件//一次读取一个字节写入一个字节的方法/*int len = 0;while((len = bis.read()) != -1){//4.使用字节缓冲输出流对象中的方法write,把读取的数据写入到内部缓冲区bos.write(len);//2毫秒}*///使用数组缓冲读取多个字节,写入多个字节byte[] bytes = new byte[1024];int len = 0;while((len = bis.read(bytes)) != -1){//4.使用字节缓冲输出流对象中的方法write,把读取的数据写入到内部缓冲区bos.write(bytes,0,len);//1毫秒}//5.释放资源(会先把缓冲切的数据,刷新到文件中)bos.close();bis.close();long e = System.currentTimeMillis();System.out.println("复制文件共耗时:" + (e-s) + "毫秒");}
}

字符缓冲流

构造方法

  • public BUfferedReader(Reader in):创建一个新的缓冲输入流
  • public BufferedWriter(Writer out):创建一个新的缓冲输出流

字符缓冲输出流

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;/*java.io.BufferedWriter extends WriterBufferedWriter:字符缓冲输出流继承自父类的共性成员方法:- void write(int c):写入单个字符。- void write(char[] cbuf):写入字符数组- abstract void write(char[] cbuf, int off, int len):写入字符数组的某一部分,off数组的开始索引,len写的字符个数。- void write(String str):写入字符串- void write(String str, int off,int len):写入字符串的某一部分,off字符串的开始索引,len写的字符个数。- void flush():刷新该流的缓冲。- void close():关闭此流,但要先刷新它构造方法:BufferedWriter(Writer out) 创建一个使用默认大小输出缓冲区的缓冲字符输出流。BufferedWriter(Writer out, int sz) 创建一个使用给定大小输出缓冲区的新缓冲字符输出流。参数:Writer out:字符输出流我们可以传递FileWriter,缓冲流会给FileWriter增加一个缓冲区,提高FileWriter的写入效率int sz:指定缓冲区的大小,不分默认大小特有的成员方法:void newLine() 写入一个行分隔符。会根据不同的操作系统,获取不同的行分隔符换行:换行符号windows:\r\nLinux:/nmac:/r使用步骤:1.创建字符缓冲输出流对象,构造方法中床底字符输出流2.调用字符缓冲输出流中的方法write,把数据写入到内存缓冲区3.调用字符缓冲输出流中的方法flush,把内存缓冲区中的数据,刷新到文件中4.释放资源*/
public class Demo03BufferedWriter {public static void main(String[] args) throws IOException {//1.创建字符缓冲输出流对象,构造方法中床底字符输出流BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\IDEA2019(中文版)\\ZXL\\src\\com\\company\\pratise\\IO\\IO_BufferedStream\\c.txt"));//2.调用字符缓冲输出流中的方法write,把数据写入到内存缓冲区for (int i = 0; i < 10; i++) {bw.write("黑美人");//bw.write("\r\n");bw.newLine();}//3.调用字符缓冲输出流中的方法flush,把内存缓冲区中的数据,刷新到文件中bw.flush();//4.释放资源bw.close();}
}

字符缓冲输入流

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;/*java.io.BufferedReader extends Reader继承自父类的共性成员方法:int read()  将字符读入数组int read(char[] cbuf) 一次读取多个字符,将字符读入数组void close() 关闭该流并释放与之关联的所有资源构造方法:BufferedReader(Reader in) 创建一个使用默认大小输入缓冲区的缓冲字符输入流。BufferedReader(Reader in, int sz) 创建一个使用指定大小输入缓冲区的缓冲字符输入流。参数:Reader in:字符输入流我们可以传递FileReader,缓冲流会给FileReader增加一个缓冲区,提高FileReader的读取效率int sz:指定缓冲区的大小,不分默认大小特有的成员方法:String readLine() 读取一个文本行。 读取一行数据行的终止符号:通过下列字符之一即可认为某行已终止:换行 ('\n')、回车 ('\r') 或回车后直接跟着换行(\r\n)返回值:包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null使用步骤:1.创建字符缓冲输入流对象,构造方法中传递字符输入流2.使用字符缓冲输入流对象中的方法read/readLine读取文本3.释放资源*/
public class Demo04BufferedReader {public static void main(String[] args) throws IOException {//1.创建字符缓冲输入流对象,构造方法中传递字符输入流BufferedReader br = new BufferedReader(new FileReader("D:\\IDEA2019(中文版)\\ZXL\\src\\com\\company\\pratise\\IO\\IO_BufferedStream\\c.txt"));//2.使用字符缓冲输入流对象中的方法read/readLine读取文本String line;while((line = br.readLine()) != null){System.out.println(line);}//3.释放资源br.close();}
}

练习:文本排序

3.侍中侍郎郭攸之、费祎、董允等,此皆良实,志虑忠纯,是以先帝简拔以遗陛下。 愚以为宫中之事,事无大小,悉以咨之,然后施行,必得裨补阙漏,有所广益。
8.愿陛下托臣以讨贼兴复之效,不效,则治臣之罪,以告先帝之灵。若无兴德之言,则责攸之、祎、允等之慢,以彰其咎:陛下亦宜自谋,以咨诹善道察纳雅言,深追先帝遗诏,臣不胜受恩感激。
4.将军向宠,性行淑均,晓畅军事,试用之于昔日,先帝称之曰能,是以众议举宠为督。愚以为营中之事,悉以咨之,必能使行阵和睦,优劣得所。
2.宫中府中,俱为一体,陟罚臧否,不宜异同。若有作奸犯科及为忠善者,宜付有司论其刑赏,以昭陛下平明之理,不宜偏私,使内外异法也。
1.先帝创业未半而中道崩殂,今天下三分,益州疲弊,此诚危急存亡之秋也。然侍卫之臣不懈于内,忠志之士忘身于外者,盖追先帝之殊遇,欲报之于陛下也。诚宜开张圣听,以光先帝遗德,恢弘志士之气,不宜妄自菲薄,引喻失义,以塞忠谏之路也。
9.今当远离,临表涕零,不知所言。
6.臣本布衣,躬耕于南阳,苟全性命于乱世,不求闻达于诸侯。先帝不以臣卑鄙,猥自枉屈,三顾臣于草庐之中,咨臣以当世之事,由是感激,遂许先帝以驱驰。后值倾覆,受任于败军之际,奉命于危难之间,尔来二十有一年矣。
7.先帝知臣谨慎,故临崩寄臣以大事也。受命以来,夙夜忧叹,恐付托不效,以伤先帝之明,故五月渡泸,深入不毛。今南方已定,兵甲已足,当奖率三军,北定中原,庶竭驾钝,攘除奸凶,兴复汉室,还于旧都。此臣所以报先帝而忠陛下之职分也。至于斟酌损益,进尽忠言,则攸之、祎、允之任也。
5.亲贤臣,远小人,此先汉所以兴隆也:亲小人,远贤臣,此后汉所以倾颓也。先帝在时,每与臣论此事,未尝不叹息痛恨于桓、灵也。侍中、尚书、长史、参军,此悉贞良死节之臣,愿陛下亲之信之,则汉室之隆,可计日而待也。

代码实现

import java.io.*;
import java.util.HashMap;/*练习:对文本的内容进行排序按照(1,2,3...)顺序排序分析:1.创建一个HashMap集合对象,key:存储每行文本的序号(1,2,3...);value:存储每行的文本2.创建字符缓冲输入流对象,构造方法中绑定字符输入流3.创建字符缓冲输出流对象,构造方法中绑定字符输出流4.使用字符缓冲输入流中的方法readLine,逐行读文本5.对读取到的文本进行切割,获取行中的序号和文本内容6.把切割好的序号和文本的内容存储到HashMap集合中(key序号是有序的,会自动排序1,2,3,4...)7.遍历HashMap集合,获取每一个键值对8.把每一个键值对,拼接为一个文本行9.把拼接好的文本,使用字符缓冲输出流中的方法write,写入到文件中10.释放资源*/
public class Demo05Test {public static void main(String[] args) throws IOException {//1.创建一个HashMap集合对象,key:存储每行文本的序号(1,2,3...);value:存储每行的文本HashMap<String,String> map = new HashMap<>();//2.创建字符缓冲输入流对象,构造方法中绑定字符输入流BufferedReader br = new BufferedReader(new FileReader("D:\\IDEA2019(中文版)\\ZXL\\src\\com\\company\\pratise\\IO\\IO_BufferedStream\\in.txt"));//3.创建字符缓冲输出流对象,构造方法中绑定字符输出流BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\IDEA2019(中文版)\\ZXL\\src\\com\\company\\pratise\\IO\\IO_BufferedStream\\out.txt"));//4.使用字符缓冲输入流中的方法readLine,逐行读文本String line;while((line = br.readLine()) != null){//5.对读取到的文本进行切割,获取行中的序号和文本内容String[] arr = line.split("\\.");//6.把切割好的序号和文本的内容存储到HashMap集合中(key序号是有序的,会自动排序1,2,3,4...)map.put(arr[0],arr[1]);}//7.遍历HashMap集合,获取每一个键值对for (String key : map.keySet()) {String value = map.get(key);//8.把每一个键值对,拼接为一个文本行line = key + "." + value;//9.把拼接好的文本,使用字符缓冲输出流中的方法write,写入到文件中bw.write(line);bw.newLine();//写换行}//10.释放资源bw.close();br.close();}
}

输出结果

1.先帝创业未半而中道崩殂,今天下三分,益州疲弊,此诚危急存亡之秋也。然侍卫之臣不懈于内,忠志之士忘身于外者,盖追先帝之殊遇,欲报之于陛下也。诚宜开张圣听,以光先帝遗德,恢弘志士之气,不宜妄自菲薄,引喻失义,以塞忠谏之路也。
2.宫中府中,俱为一体,陟罚臧否,不宜异同。若有作奸犯科及为忠善者,宜付有司论其刑赏,以昭陛下平明之理,不宜偏私,使内外异法也。
3.侍中侍郎郭攸之、费祎、董允等,此皆良实,志虑忠纯,是以先帝简拔以遗陛下。 愚以为宫中之事,事无大小,悉以咨之,然后施行,必得裨补阙漏,有所广益。
4.将军向宠,性行淑均,晓畅军事,试用之于昔日,先帝称之曰能,是以众议举宠为督。愚以为营中之事,悉以咨之,必能使行阵和睦,优劣得所。
5.亲贤臣,远小人,此先汉所以兴隆也:亲小人,远贤臣,此后汉所以倾颓也。先帝在时,每与臣论此事,未尝不叹息痛恨于桓、灵也。侍中、尚书、长史、参军,此悉贞良死节之臣,愿陛下亲之信之,则汉室之隆,可计日而待也。
6.臣本布衣,躬耕于南阳,苟全性命于乱世,不求闻达于诸侯。先帝不以臣卑鄙,猥自枉屈,三顾臣于草庐之中,咨臣以当世之事,由是感激,遂许先帝以驱驰。后值倾覆,受任于败军之际,奉命于危难之间,尔来二十有一年矣。
7.先帝知臣谨慎,故临崩寄臣以大事也。受命以来,夙夜忧叹,恐付托不效,以伤先帝之明,故五月渡泸,深入不毛。今南方已定,兵甲已足,当奖率三军,北定中原,庶竭驾钝,攘除奸凶,兴复汉室,还于旧都。此臣所以报先帝而忠陛下之职分也。至于斟酌损益,进尽忠言,则攸之、祎、允之任也。
8.愿陛下托臣以讨贼兴复之效,不效,则治臣之罪,以告先帝之灵。若无兴德之言,则责攸之、祎、允等之慢,以彰其咎:陛下亦宜自谋,以咨诹善道察纳雅言,深追先帝遗诏,臣不胜受恩感激。
9.今当远离,临表涕零,不知所言。

转换流

字符编码和字符集

字符编码

计算机中储存的信息都是用二进制数表示的,而我们在屏幕上看到的数字、英文、标点符号、汉字等字符是二进制数转换之后的结果。按照某种规则,将字符存储到计算机中,称为编码。反之,将存储在计算机中的二进制数按照某种规则解析显示出来,称为解码。比如说,按照A规则存储,同样按照A规则解析,那么就能显示正确的文本符号。反之,按照A规则存储,再按照B规则解析,就会导致乱码现象。
编码:字符(能看懂的)–>字节(看不懂的)
解码:字节(看不懂的)–>字符(能看懂的)

  • 字符编码Character Encoding:就是一套自然语言的字符与二进制数之间的对应规则。
  • 编码表:生活中文字和计算机中二进制的对应规则

字符集

  • 字符集Charset:也叫编码表。是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符、数字等

计算机要准确的存储和识别各种字符集符号,需要进行字符编码,一套字符集必然至少要有一套字符编码。常见字符集有ASCII字符集、CBK字符集、Unicode字符集等。

编码 字符集
ASCII编码 ASCII字符集
GBK编码 GBK字符集
UTF-8编码、UTF-16编码、UTF-32编码 Unicode字符集
  • ASCII字符集

    • ASCII (American Standard Code for Information Interchange,美国信息交换标准代码)是基于拉丁字母的一套电脑编码系统,用于显示现代英语,主要包括控制字符(回车键、退格、换行键等)和可显示字符(英文大小写字符、阿拉伯数字和西文符号)。
    • 基本的ASCII字符集,使用7位(bits)表示一个字符,共128字符。ASCII的扩展字符集使用8位(bits)表示一个字符,共256字符,方便支持欧洲常用字符。
  • ISO-8859-1字符集:

    • 拉丁码表,别名Latin-1,用于显示欧洲使用的语言,包括荷兰、丹麦、德语、意大利语、西班牙语等。
    • ISO-8859-1使用单字节编码,兼容ASCIl编码。
  • GBxxx字符集:

    • GB就是国标的意思,是为了显示中文而设计的一套字符集。
    • GB2312:简体中文码表。一个小于127的字符的意义与原来相同。但两个大于127的字符连在一起时,就表示一个汉字,这样大约可以组合了包含7000多个简体汉字,此外数学符号、罗马希腊的字母、日文的假名们都编进去了,连在ASCII里本来就有的数字标点字母都统统重新编了两个字节长的编码,这就是常说的"全角”字符,而原来在127号以下的那些就叫"半角”字符了。
    • GBK:最常用的中文码表。是在GB2312标准基础上的扩展规范,使用了双字节编码方案,共收录了21003个汉字,完全兼容GB2312标准,同时支持繁体汉字以及日韩汉字等。
    • GB18030:最新的中文码表。收录汉字70244个,采用多字节编码,每个字可以由1个、2个或4个字节组成支持中国国内少数民族的文字,同时支持警体汉字以及日韩汉字等
  • Unicode字符集

    • Unicode编码系统为表达任意语言的任意字符而设计,是业界的一种标准,也称为统一码、标准万国码。
    • 它最多使用4个字节的数字来表达每个字母符号,或者文字。有三种编码方案,UTF-8、UTF-16和UTF32。最为常用的UTF-8编码。
    • UTF-8编码,可以用来表示Unicode标准中任何字符,它是电子邮件、网页及其他存储或传送文字的应用中,优先采用的编码。互联网工程工作小组(IETF)要求所有互联网协议都必须支持UTF-8编码。所以,我们开发Web应用,也要使用UTF-8编码。它使用一至四个字节为每个字符编码,编码规则:
      1. 128个US-ASCII字符,只需一个字节编码
      2. 拉丁文等字符重要一个字节编码
      3. 大部分常用字(含中文),使用三个字节编码
      4. 其他极少使用的Unicode辅助字符,使用四字节编码。

编码引出的问题

在IDEA中,使用FileReader读取项目中的文本文件。由于IDEA的设置,都是默认的UTF-8编码,所以没有任何问题。但是,当读取Windows系统中创建的文本文件中,由于Windows系统的默认是GBK编码,就会出现乱码。

import java.io.FileReader;
import java.io.IOException;/*FileReader可以读取IDEA默认编码格式(UTF-8)的文件FileReader读取系统默认编码(中文GBK)会产生乱码*/
public class Demo01FileReader {public static void main(String[] args) throws IOException {FileReader fr = new FileReader("D:\\IDEA2019(中文版)\\ZXL\\study\\src\\study\\java\\IO\\IO_ReverseStream\\我是GBK格式的文本.txt");int len = 0;while((len = fr.read()) != -1){System.out.println((char)len);}fr.close();}
}

OutputStreamWriter类

转换流java.io.OutputStreamWriter 是Writer的子类,是从字符流到字节流的桥梁。使用指定的字符集将字符编码为字节。它的字符集可以由名称指定,也可以接受平台的默认字符集。

构造方法

  • OutputStreamwriter(OutputStreamin):创建一个使用默认字符集的字符流。
  • OutputStreamwriter(OutputStream out, String charsetName):创建一个指定字符集的字符流。
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;/*java.io.OutputStreamWriter extends WriterOutputStreamWriter:是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。(编码):把能看懂的编程看不懂继承自父类的共性成员方法:- void write(int c):写入单个字符。- void write(char[] cbuf):写入字符数组- abstract void write(char[] cbuf, int off, int len):写入字符数组的某一部分,off数组的开始索引,len写的字符个数。- void write(String str):写入字符串- void write(String str, int off,int len):写入字符串的某一部分,off字符串的开始索引,len写的字符个数。- void flush():刷新该流的缓冲。- void close():关闭此流,但要先刷新它构造方法:OutputStreamWriter(OutputStream out) 创建使用默认字符编码的 OutputStreamWriter。OutputStreamWriter(OutputStream out, String charsetName) 创建使用指定字符集的 OutputStreamWriter。参数:OutputStream out:字节输出流,可以用来写转换之后的字节到文件中String charsetName:指定的编码表名称,不区分大小写utf-8/UTF-8,GBK/gbk...,不默认使用UTF-8使用步骤:1.创建OutputStreamWriter对象,构造方法中传递字节输出流和指定编码表名称2.使用OutputStreamWriter对象中的方法write,把字符转换为字节存储缓冲区中(编码)3.使用OutputStreamWriter对象中的方法flush,把内容缓冲区中的字节刷新到文件中(使用字节流写字节的过程)4.释放资源*/
public class Demo02OutputStreamWriter {public static void main(String[] args) throws IOException {//writer_utf_8();write_gbk();}/*使用转化流OutputStreamWriter写GBK格式的文件*/private static void write_gbk() throws IOException {//1.创建OutputStreamWriter对象,构造方法中传递字节输出流和指定编码表名称OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("D:\\IDEA2019(中文版)\\ZXL\\study\\src\\study\\java\\IO\\IO_ReverseStream\\gbk.txt"),"GBK");//2.使用OutputStreamWriter对象中的方法write,把字符转换为字节存储缓冲区中(编码)osw.write("你好");//3.使用OutputStreamWriter对象中的方法flush,把内容缓冲区中的字节刷新到文件中(使用字节流写字节的过程)osw.flush();//4.释放资源osw.close();}/*使用转化流OutputStreamWriter写UTF-8格式的文件*/private static void writer_utf_8() throws IOException {//1.创建OutputStreamWriter对象,构造方法中传递字节输出流和指定编码表名称OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("D:\\IDEA2019(中文版)\\ZXL\\study\\src\\study\\java\\IO\\IO_ReverseStream\\utf_8.txt"),"UTF-8");//2.使用OutputStreamWriter对象中的方法write,把字符转换为字节存储缓冲区中(编码)osw.write("你好");//3.使用OutputStreamWriter对象中的方法flush,把内容缓冲区中的字节刷新到文件中(使用字节流写字节的过程)osw.flush();//4.释放资源osw.close();}
}

InputStreamrReader类

转换流java.io.InputStreaReader,是Reader的子类,是从字节流到字符流的桥梁。它读取字节,并使用指定的支付及将其解码为字符。它的字符集可以由名称指定,也可以接受平台恶默认字符集。

构造方法

  • InputStreamReader(InputStream in):创建一个使用默认字符集的字符流
  • InputStreamReader(InputStream in, String charsetName):创建一个指定字符集的字符流
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;/*java.io.InputStreamReader extends ReaderInputStreamReader:是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。(解码):把看不懂的变成看得懂继承自父类的共性成员方法:、int read()  将字符读入数组int read(char[] cbuf) 一次读取多个字符,将字符读入数组void close() 关闭该流并释放与之关联的所有资源构造方法:InputStreamReader(InputStream in) 创建一个使用默认字符集的 InputStreamReader。InputStreamReader(InputStream in, String charsetName) 创建使用指定字符集的 InputStreamReader。参数:InputStream in:字节输入流,用来读取文件中保存的字节String charsetName:指定的编码表名称,不区分大小写utf-8/UTF-8,GBK/gbk...,不默认使用UTF-8使用步骤:1.创建InputStreamReader对象,构造方法中传递字节输入流和指定的编码表名称2.使用InputStreamReader对象中的方法read读取文件3.释放资源注意事项:构造方法中指定的编码表名称要和文件的编码相同,否则会发生乱码*/
public class Demo03InputStreamReader {public static void main(String[] args) throws IOException {//read_utf_8();read_gbk();}/*使用InputStreamReader读取gbk格式的文件*/private static void read_gbk() throws IOException {//1.创建InputStreamReader对象,构造方法中传递字节输入流和指定的编码表名称InputStreamReader isr = new InputStreamReader(new FileInputStream("D:\\IDEA2019(中文版)\\ZXL\\study\\src\\study\\java\\IO\\IO_ReverseStream\\gbk.txt"),"gbk");//InputStreamReader isr = new InputStreamReader(new FileInputStream("D:\\IDEA2019(中文版)\\ZXL\\study\\src\\study\\java\\IO\\IO_ReverseStream\\gbk.txt"),"utf-8");//???//2.使用InputStreamReader对象中的方法read读取文件int len = 0;while((len = isr.read()) != -1){System.out.println((char)len);}//3.释放资源isr.close();}/*使用InputStreamReader读取utf-8格式的文件*/private static void read_utf_8() throws IOException {//1.创建InputStreamReader对象,构造方法中传递字节输入流和指定的编码表名称InputStreamReader isr = new InputStreamReader(new FileInputStream("D:\\IDEA2019(中文版)\\ZXL\\study\\src\\study\\java\\IO\\IO_ReverseStream\\utf_8.txt"),"utf-8");//2.使用InputStreamReader对象中的方法read读取文件int len = 0;while((len = isr.read()) != -1){System.out.println((char)len);}//3.释放资源isr.close();}
}

转换流原理图解

转换文件编码

将GBK编码的文本文件,转换为UTF-8编码的文件

案例分析

  1. 指定GBK编码的转换流,读取文本文件
  2. 使用UTF-8编码的转换流,写出文本文件

案例实现

import java.io.*;/*练习:转换文件编码将GBK编码的文本文件,转换为UTF-8编码的文件分析:1.创建InputStreamReader对象,构造方法中传递字节输入流和指定的编码表名称GBK2.创建OutputStreamWriter对象,构造方法中传递字节输出流和指定的表码表名称UTF-83.使用InputStreamReader对象方法read读取文件4.使用OutputStreamWriter对象中的方法write。把读取的数据写入到文件中5.释放资源*/
public class Demo04Test {public static void main(String[] args) throws IOException {//1.创建InputStreamReader对象,构造方法中传递字节输入流和指定的编码表名称GBKInputStreamReader isr = new InputStreamReader(new FileInputStream("D:\\IDEA2019(中文版)\\ZXL\\study\\src\\study\\java\\IO\\IO_ReverseStream\\我是GBK格式的文本.txt"),"GBK");//2.创建OutputStreamWriter对象,构造方法中传递字节输出流和指定的表码表名称UTF-8OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("D:\\IDEA2019(中文版)\\ZXL\\study\\src\\study\\java\\IO\\IO_ReverseStream\\我是utf-8格式的文本.txt"),"utf-8");//3.使用InputStreamReader对象方法read读取文件int len = 0;while((len = isr.read()) != -1){//4.使用OutputStreamWriter对象中的方法write。把读取的数据写入到文件中osw.write(len);}//5.释放资源osw.close();isr.close();}
}

序列化

概述

Java提供了一种对象序列化的机制。用一个字节序列可以表示一个对象,该字节序列包含该对象的数据对象的类型对象中存储的属性等信息。字节序列写出到文件之后,相当于文件中持久保存了一个对象的信息。

反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化对象的数据对象的类型对象中存储的数据信息,都可以用来在内存中创建对象。看图理解序列化:

ObjectOutputStream类

java.io.ObjectOutputStream类,将java对象的原始数据类型写到文件,实现对象的持久存储

构造方法

  • public ObjectOutputStream(OutputStream out):创建一个指定的OutputStream的ObjectOutputStream。

序列化操作

Demo01ObjectOutputStream.java

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;/*java.io.ObjectOutputStream extends OutputStreamObjectOutputStream:对象的序列化流作用:把对象以流的方式写入到文件中保存构造方法:ObjectOutputStream(OutputStream out) 创建写入指定 OutputStream 的 ObjectOutputStream。参数:OutputStream out:字节输出流特有的成员方法:void writeObject(Object obj) 将指定的对象写入 ObjectOutputStream。使用步骤:1.创建ObjectOutputStream对象,构造方法中传递字节输出流2.使用ObjectOutputStream对象中的方法writeObject,把对象写入到文件中3.释放资源*/
public class Demo01ObjectOutputStream {public static void main(String[] args) throws IOException {//1.创建ObjectOutputStream对象,构造方法中传递字节输出流ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\IDEA2019(中文版)\\ZXL\\study\\src\\study\\java\\IO\\IO_ObjectStream\\person.txt"));//2.使用ObjectOutputStream对象中的方法writeObject,把对象写入到文件中oos.writeObject(new Person("小美女",18));//3.释放资源oos.close();}
}

Person.java

import java.io.Serializable;/*序列化和反序列化的时候会抛出NotSerializableException没有序列化异常类通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。Serializable接口也叫标记型接口要进行序列化和反序列化的类必须实现Serializable接口,就会给类添加一个标记当我们进行序列化和反序列化的时候,就会检测类上是否有这个标记有:就可以序列化和反序列化没有:就会抛出NotSerializableException异常去市场买肉-->肉上有一个蓝色章(检测合格)-->放心购买-->买回来怎么吃随意static关键字:静态关键字静态优先于非静态加载爱内存中(静态优先于对象进入到内存中)被static修饰的成员变量不能被序列化,序列化的都是对象transient关键字:瞬态关键字被transient修饰成员变量,不能被序列化*/
public class Person implements Serializable {private String name;//private transient int age;private int age;public Person() {}public Person(String name, int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}

ObjectInputStream类

ObjectInputStream反序列化流,将之前使用ObjectOutputStream序列化的原始数据恢复为对象

构造方法

  • public ObjectInputStream(InputStream In):创建一个指定的InputStream的ObjectInputStream。

反序列化操作1

如果能找到一个对象的class文件,我们可以进行反序列化操作,调用ObjectInputStream读取对象的方法:

  • public final object readObject():从ObjectInputStream读取一个对象
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;/*java.io.ObjectInputStream extends InputStreamObjectInputStream :对象的反序列化流作用:把文件中保存的对象,以流的方式读取出来使用构造方法:ObjectInputStream(InputStream in) 创建从指定 InputStream 读取的 ObjectInputStream。参数:InputStream in:字节输入流特有的成员方法:object readObject() 从ObjectInputStream读取对象使用步骤:1.创建ObjectInputStream对象,构造方法中传递字节输入流2.使用ObjectInputStream对象中的方法readObject读取保存对象的文件3.释放资源4.使用读取出来的对象(打印)readObject方法声明抛出了ClassNotFoundException(class文件找不到异常)当不存在对象的class文件时抛出此异常反序列化的前提:1.类必须实现Serializable2.必须存在类对应的class文件*/
public class Demo02ObjectInputStream {public static void main(String[] args) throws IOException, ClassNotFoundException {//1.创建ObjectInputStream对象,构造方法中传递字节输入流ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\IDEA2019(中文版)\\ZXL\\study\\src\\study\\java\\IO\\IO_ObjectStream\\person.txt"));//2.使用ObjectInputStream对象中的方法readObject读取保存对象的文件Object o = ois.readObject();//3.释放资源ois.close();//4.使用读取出来的对象(打印)System.out.println(o);Person p = (Person)o;System.out.println(p.getName() + "=" + p.getAge());}
}

反序列化操作2

当JVM反序列化对象时,能找到class文件,但是class文件在序列化对象之后发生了修改,那么反序列化操作也会失败,抛出一个InvalidclassException异常。发生这个异常的原因如下:

  • 该类的序列版本号与从流中读取的类描述符的版本号不匹配
  • 该类包含未知数据类型
  • 该类没有可访问的无参数构造方法

Serializable接口给需要序列化的类,提供了一个序列版本号。 serialVersionuID 该版本号的目的在于验证序列化的对象和对应类是否版本匹配。

序列号冲突异常的原理和解决方案

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n9Mox8qO-1622979218306)(D:\朱相龙\java学习\笔记\图片\序列号冲突异常的原理和解决方案.png)]

练习:序列化集合

  1. 将存有多个自定义对象的集合序列化操作,保存到list.txt文件中。
  2. 反序列化list.txt,并遍历集合,打印对象信息

案例分析

  1. 把若干学生对象,保存到集合中
  2. 把集合序列化
  3. 反序列化读取时,只需要读取一次,转换为集合类型
  4. 遍历集合,可以打印所有的学生信息

案例实现

import java.io.*;
import java.util.ArrayList;/*练习:序列化集合当我们想在文件中保存多个对象的时候可以把多个对象存储到一个集合中对集合进行序列化和反序列化分析:1.定义一个存储Person对象的ArrayList集合2.往ArrayList集合中存储Person对象3.创建一个序列化流ObjectOutputStream对象4.使用ObjectOutputStream对象中的方法writeObject,对集合进行序列化5.创建一个反序列化ObjectInputStream对象6.使用ObjectInputStream对象中的方法readObject读取文件中保存的集合7.把Object类型的集合转换为ArrayList类型8.遍历ArrayList集合9.释放资源*/
public class Demo03Test {public static void main(String[] args) throws IOException, ClassNotFoundException {//1.定义一个存储Person对象的ArrayList集合ArrayList<Person> list = new ArrayList<>();//2.往ArrayList集合中存储Person对象list.add(new Person("张三",18));list.add(new Person("李四",19));list.add(new Person("王五",20));//3.创建一个序列化流ObjectOutputStream对象ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\IDEA2019(中文版)\\ZXL\\study\\src\\study\\java\\IO\\IO_ObjectStream\\list.txt"));//4.使用ObjectOutputStream对象中的方法writeObject,对集合进行序列化oos.writeObject(list);//5.创建一个反序列化ObjectInputStream对象ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\IDEA2019(中文版)\\ZXL\\study\\src\\study\\java\\IO\\IO_ObjectStream\\list.txt"));//6.使用ObjectInputStream对象中的方法readObject读取文件中保存的集合Object o = ois.readObject();//7.把Object类型的集合转换为ArrayList类型ArrayList<Person> list2 = (ArrayList<Person>)o;//8.遍历ArrayList集合for (Person p : list2) {System.out.println(p);}//9.释放资源ois.close();oos.close();}
}

打印流

概述

平时我们在控制台打印输出,是调用printprintln方法完成的,这两个方法都来自于java.io.PrintStream类,该类能够方便地打印各种数据类型的值,是一种便捷的输出方法

PrintStream类

  • public PrintStream(Strin fileName):使用指定的文件名创建一个新的打印流

Demo01PrintStream.java

import java.io.FileNotFoundException;
import java.io.PrintStream;/*java.io.PrintStream:PrintStream 为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。PrintStream特点:1.只负责数据的输出,不负责数据的读写2.与其他输出流不同,PrintStream永远不会抛出IOException异常3.有特有的方法,print,printlnvoid print(任意类型的值)void println(任意类型的值并换行)构造方法:PrintStream(File file):输出的目的地是一个文件PrintStream(OutputStream out):输出的目的地是一个字节输出流PrintStream(String fileName):输出的目的地是一个文件路径PrintStream extends OutputStream继承自父类的成员方法:- public void close(): 关闭此输出流并释放与此流相关联的任何系统资源- public void flush(): 刷新此输出流并强制任何缓冲的输出字节被写出。- public void write(byte[]b):将b.length字节从指定的字节数组写入此输出流。- public void write(byte[]b, int off, int len):从指定的字节数组写入len字节,从偏移量off开始输出到此输出流。- public abstract void write(int b) :将指定的字节输出流注意:1.如果使用继承自父类的write方法写数据,那么查看数据的时候会查询编码表 97->a2.如果使用自己特有的方法print/println方法写数据,写的数据原样输出 97->97*/
public class Demo01PrintStream {public static void main(String[] args) throws FileNotFoundException {//创建一个打印流PrintStream对象,构造方法中绑定要输出的目的地PrintStream ps = new PrintStream("D:\\IDEA2019(中文版)\\ZXL\\study\\src\\study\\java\\IO\\IO_PrintStream\\print.txt");//如果使用继承自父类的write方法写数据,那么查看数据的时候会查询编码表 97->aps.write(97);//如果使用自己特有的方法print/println方法写数据,写的数据原样输出 97->97ps.println(97);ps.println(8.8);ps.println('a');ps.println("HelloWorld");ps.println(true);//释放资源ps.close();}
}

Demo02PrintStream.java

import java.io.FileNotFoundException;
import java.io.PrintStream;/*可以改变输出语句的目的地(打印流的流向)输出语句,默认在控制台输出使用System.setOut方法改变输出语句的目的地改为参数中传递的打印流的目的地static void setOut(PrintStream out) 重新分配“标准”输出流*/
public class Demo02PrintStream {public static void main(String[] args) throws FileNotFoundException {System.out.println("我是在控制台输出");PrintStream ps = new PrintStream("D:\\IDEA2019(中文版)\\ZXL\\study\\src\\study\\java\\IO\\IO_PrintStream\\目的地是打印流.txt");System.out.println(ps);//把输出语句的目的地改变为打印流的目的地System.out.println("我在打印流的目的地中输出");ps.close();}
}

java.io的缓冲流、转换流、序列化流相关推荐

  1. Java基础-22总结登录注册IO版,数据操作流,内存操作流,打印流,标准输入输出流,转换流,随机访问流,合并流,序列化流,Properties...

    你需要的是什么,直接评论留言. 获取更多资源加微信公众号"Java帮帮" (是公众号,不是微信好友哦) 还有"Java帮帮"今日头条号,技术文章与新闻,每日更新 ...

  2. 【Java基础】Java IO编程:输入输出流、内存流、打印流、缓冲流BufferedReader、扫描流Scanner、序列化与反序列化

    文章目录 第11章.Java IO编程 11.1 文件操作类:File 11.2 字节流与字符流 字节输出流:OutputStream OutputStream类 FileOutputStream类 ...

  3. Java基础-22总结登录注册IO版,数据操作流,内存操作流,打印流,标准输入输出流,转换流,随机访问流,合并流,序列化流,Properties

    你需要的是什么,直接评论留言. 获取更多资源加微信公众号"Java帮帮" (是公众号,不是微信好友哦) 还有"Java帮帮"今日头条号,技术文章与新闻,每日更新 ...

  4. File类,字节字符输入输出流,缓冲流,标准流,对象序列化流

    一,File文件类 1 File类创建功能:    public boolean createNewFiLe():当具有该名称的文件不存在时,创建一个由该抽象路径名命名的新空文件       如果文件 ...

  5. 集合到文件 文件到集合 点名器 集合到文件数据排序版 标准输入流 打印流 对象序列化流 对象返序列化流 Properties 游戏次数 进程和线程 线程 多线程的实现方式 设置和获取线程名称

    文章目录 集合到文件 文件到集合 点名器 集合到文件数据排序版 标准输入流 打印流 对象序列化流 对象返序列化流 Properties 游戏次数 进程和线程 线程 多线程的实现方式 设置和获取线程名称 ...

  6. java(IO)读写文件乱码转换UTF-8问题

    java(IO)读写文件乱码转换UTF-8问题 读取文件String Content = ""; // 文件很长的话建议使用StringBuffertry {FileInputSt ...

  7. IO流案例以及特殊操作流/对象对象序列化流/Properties集合

    文章目录 IO流案例 复制单级文件夹 复制多级文件夹 IO特殊操作流 标准输入流 字节打印流 字符打印流 对象序列化流 serialVersionUID&transient Propertie ...

  8. Java IO学习笔记(四)打印流

    1.只有输出流才有打印流:PrintWriter和PrintStream分别针对字符和字节,提供了重载的print,Println方法用于多种数据类型的输出.PrintWriter和PrintStre ...

  9. [已解决]报异常java.io.InvalidClassException的解决方法|对象序列化实现Serializable会出现java.io.InvalidClassException的异常

    一.前言 今天在增加完新功能后, 部署的时候,突然就遇到了java.io.InvalidClassException的问题,这些都是我们平常不注意细节造成的后果. 具体异常如下 分析异常:Caused ...

  10. java缓存流速度与硬盘_系统学习 Java IO (九)----缓冲流 BufferedInputStream/BufferedOutputStream...

    BufferedInputStream BufferedInputStream 类为输入流提供缓冲. 缓冲可以加快IO的速度. BufferedInputStream 不是一次从网络或磁盘读取一个字节 ...

最新文章

  1. pat1004. Counting Leaves (30)
  2. opencl 实例源码
  3. java c3p0 配置文件_【c3p0】 C3P0的三种配置方式以及基本配置项详解
  4. HTML 5 样式指南和代码约定
  5. C#中小数点后保留两位小数,四舍五入的函数及使用方法
  6. Linux:-bash: ***: command not found
  7. c++ pdflib输出表格_DescrTab2包,输出SCI级别的描述统计表
  8. 阿里带火的中台,究竟是个啥?
  9. cake 简单思维题
  10. mysql 流浪,流浪汉机器 – 如何找出mysql用户名/密码
  11. CodeForces 621C 数学概率期望计算
  12. Skiing POJ 3037 很奇怪的最短路问题
  13. MOOC 研究生学术与职业素养 课后答案
  14. 迅雷不及掩耳 山寨版iPhone 5令人瞠目
  15. 符号——Alt+数字键
  16. 百家讲坛之评说《资治通鉴》之探寻历史的密码
  17. 使用kaminari实现分页
  18. Altium Designer如何批量修改SCH名称,数值,封装
  19. 服务端使用GZIP压缩数据
  20. 傅里叶变换、拉普拉斯变换、z变换之间的联系

热门文章

  1. css的sprites什么意思,CSS Sprites是什么
  2. 前端开发step1,2,3
  3. 3、ORBSLAM闭环检测终局之战之sim3计算流程,确定是否检测到闭环
  4. 80个Python经典资料(教程+源码+工具)汇总
  5. 【洞见研报】网络游戏薪酬报告(薪酬报告,网络游戏,游戏公司岗位)
  6. Hulu 2020年校招-算法题《Hulu杀》Python
  7. 马云的“虚拟信用卡”动了谁的奶酪?
  8. unity之粒子特效制作图片拼合文字效果
  9. 腾讯历届笔试题(1)
  10. MySQL 百分比排序