【自用】JavaSE--IO流(二)--缓冲流、转换流、打印流、数据流、序列化流、IO框架
缓冲流
缓冲流的作用:对原始流进行包装,提升原始流读写数据的性能
字节缓冲流
也可以自定义缓冲池的大小,写法示例: InputStream is_buffer = new BufferedInputStream(is, 8192*2);
示例:
代码:
public class test {public static void main(String[] args){try (InputStream is = new FileInputStream("D:\\Desktop\\备份\\萌萌香.png");OutputStream os = new FileOutputStream("D:\\Desktop\\test\\萌萌香.png");//将两个原始流封装成缓冲流InputStream is_buffer = new BufferedInputStream(is, 8192*2);//也可以自己定义缓冲池大小OutputStream os_buffer = new BufferedOutputStream(os, 8192*2);){byte[] buffer = new byte[1024];//一次读1024B,即 1KBint len; //每次读取到的字节数while( (len=is_buffer.read(buffer))!=-1 ){os_buffer.write(buffer,0,len);}System.out.println("复制成功!");} catch (Exception e) {e.printStackTrace();}}
}
字符缓冲流
字符缓冲输入流
原理与字节缓冲流基本一致,不过是单位从字节变成字符罢了
读取的操作与原始流读取的操作完全一致,就是多了一步将原始流包装成缓冲流的步骤
readline案例(readline是BufferedReader的特有方法,因此不能采用多态的写法):
字符缓冲输出流
原理与字节缓冲输出流类似
示例(执行3次):
案例
将乱序的句子排完序且复制到新文件中去
注意: . $ | * 等转义字符,必须得加 \\ 用\表示\是转义字符
代码(自己写版):
public class copy_Demo {public static void main(String[] args) {try (BufferedReader brd = new BufferedReader(new FileReader("File-IO\\src\\com\\CJ\\unsorted"));BufferedWriter bwr = new BufferedWriter(new FileWriter("File-IO\\src\\com\\CJ\\sorted"))){//把所有句子装进集合List<String> sentences = new ArrayList<>();String line;while( (line= brd.readLine())!=null ){sentences.add(line);}//排序Collections.sort(sentences, new Comparator<String>() {@Overridepublic int compare(String o1, String o2) {String[] split1 = o1.split("\\.");String[] split2 = o2.split("\\.");return Integer.valueOf(split1[0])-Integer.valueOf(split2[0]);}});//去掉序号for(int i=0;i<sentences.size();i++){String[] s = sentences.get(i).split("\\.");sentences.set(i,s[1]);}//复制到新文件去for(int i=0;i<sentences.size();i++){bwr.write(sentences.get(i));bwr.newLine();}System.out.println("已排序完且复制到新文件中!");} catch (Exception e) {e.printStackTrace();}}
}
代码(优化版):
public class copy_Demo {public static void main(String[] args) {try (BufferedReader brd = new BufferedReader(new FileReader("File-IO\\src\\com\\CJ\\unsorted"));BufferedWriter bwr = new BufferedWriter(new FileWriter("File-IO\\src\\com\\CJ\\sorted"))){//把所有句子装进集合List<String> sentences = new ArrayList<>();String line;while( (line= brd.readLine())!=null ) sentences.add(line);//排序Collections.sort(sentences, (o1, o2) -> Integer.valueOf(o1.substring(0,o1.indexOf('.')))-Integer.valueOf(o2.substring(0,o2.indexOf('.'))));//去掉序号for(int i=0;i<sentences.size();i++){String s = sentences.get(i);s = s.substring(s.indexOf('.')+1);sentences.set(i,s);}//复制到新文件去for(String s : sentences){bwr.write(s);bwr.newLine();}System.out.println("已排序完且复制到新文件中!");} catch (Exception e) {e.printStackTrace();}}
}
性能分析
可以通过 System.currentTimeMillis() 获取系统时间,只要在程序执行最开始和最后分别获取时间(单位为毫秒),再相减就能得知程序运行时间
通过这种方法分别测试原始流和缓冲流就能得知缓冲流的速度明显快很多
采用的字节数组越大,性能越强,但当字节数组大到一定程度时对性能的提升微乎其微,但却消耗了大量的时间,理解为用空间换时间了,因此还是需要选取一个适合应用场景的字节数组大小
转换流
可能出现的问题:编码解码不一致导致读取的文件出现乱码
比如在java中使用UTF-8进行编码,然后想要读取一个文件,但是这个文件是GBK编码的,此时执行程序就会发生乱码
解决办法 ---> 转换流
字符输入转换流
示例(这里的test.txt采用GBK编码):
如果不指定转换流的编码,则使用默认编码,我这里java的编码为UTF-8,会出现乱码,如下图
字符输出转换流
和上面差不多,也是指定一个字符集编码,之后输出都是按照指定的字符集编码的
示例:
打印流
可以实现更方便、更高效的打印数据出去,能实现打印啥出去就是啥出去(打印97就是97,不会变成a)
PrintStream
示例:
PrintWriter
与PrintStream几乎一样,PrintWriter继承于字符输出流,因此PrintWriter的write方法支持写的数据类型更多更多
扩展:如何追加数据
由于打印流是高级流,并不支持直接在文件中追加数据,但可以通过 封装低级的支持追加数据的流 从而实现追加数据,示例如下:
案例:输出语句的重定向
平时使用sout输出的数据会打印到控制台,而打印流可以改变输出的位置,比如输出到文件里去,这种操作就称为输出语句的重定向
使用 System.setOut(打印流名); 修改系统默认的打印流,系统默认的打印流就是输出到控制台的
示例:
数据流
数据输出流
同时将数据类型与数据类型存在文件中,不是乱码,是把数据和其类型一并存进去了(这种数据输出流,把数据存到文件里去,不是为了给人阅读的,是为了存进去,方便下次又能读出来)
写的数据和读的数据顺序要一样,示例如下,与上面存入的一致
序列化流
对象序列化:把java对象写到文件中去
对象反序列化:把文件中的对象读出来
序列化流就是用来写对象或读对象的
对象字节输入流
如果对象需要序列化,则必须要实现序列化接口Serializable
序列化接口相当于是一个标记,它是给jvm虚拟机程序看的。这个对象只有实现虚拟实现序列化接口,jvm才能够允许这个对象按照特定的方式存入到文件中去。
示例:
对象字节输出流
反序列化操作时并不知道具体的对象类型是什么,因此返回了个Object类型,自己强转即可
示例:
扩展1:有不想序列化的变量怎么办
在对象中不想序列化的变量前加上transient修饰符,这样该变量就不会参与序列化
扩展2:如何一次序列化多个对象
把对象放到ArrayList集合里,直接对ArrayList进行序列化
IO框架
怎么理解,一个框架里有很多类,类里面有很多方法,这些方法就是一些经常会用到的操作,比如复制、粘贴、删除等。就是一些高手造好了轮子给大家拿来用
一般这些框架都是第三方开发的,因此想要使用就必须要先下载过来才能使用
Commons-io框架
可以直接通过文件复制,也可以通过流来复制
两个常用类:FileUtils、IOUtils,对应常用方法如下图:
如何导入框架
lib翻译为库,基本上就是拿来放框架的
补充
java官方在后来的版本更新中也提供了一个 Files类,支持一行代码完成复制等操作
但commons-io还是更强大一些