零基础学习java------day17------缓冲字节流,转换字节流,简化流,缓冲字符流,序列化和对象流
1. 缓冲字节流
缓冲区:缓冲区实质上是一个数组。通常它是一个字节数组,但是也可以使用其他种类的数组。但是一个缓冲区不 仅仅 是一个数组。缓冲区提供了对数据的结构化访问,而且还可以跟踪系统的读/写进程。
缓冲流出现的原因:使用字节流每次从文件中进行读写的时候,都需要和文件进行大量的IO交互,与磁盘交互的效率其实是比较低的,所以为了降低与磁盘的交互次数,可以使用字节缓冲流。字节缓冲流将数据放到缓存区,而缓冲区是一个内存区域的概念,我们直接和缓冲区做交互,可以提升效率。
注意:
(1)什么时候缓冲区的数据写入硬盘中?
当缓冲区被写满时,或是使用flush方法将至写入硬盘(注意关流后,缓存区的内容会被写入硬盘,因为关流内部会调用flush方法)
(2)byte数组的大小要小于缓存区,缓存区的数据是通过数组间接读入的
1.1 缓冲字节输出流
BufferOutputStream(OutputStream);
1.1.1 构造方法:
(1)public BufferedOutputStream(OutputStream out)
(2)public BufferedOutputStream(OutputStream out, int size): 此处参数size表示缓冲区的大小,默认是8kb
1.1.2 成员方法:
(1)public void write(int b)
(2)public void write(byte b[])
(3)public void write(byte b[], int off, int len):off表示偏移量,len表示从偏移量位置开始写入数据的长度
(4)public void flush(): 刷新,将缓存区的内容写到文件中,一般只有带缓冲的输出流才有这样的方法
public class BufferOutputStreamDemo { public static void main(String[] args) { try ( BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("e:/a.txt")); ){ bos.write("妈妈,他们抛弃了我".getBytes());//妈妈,他们抛弃了我 bos.write(97); //a bos.write("妈妈,他们抛弃了我".getBytes(),0,6);//妈妈 bos.flush(); //一般使用输出流的时候,尽量把flish写出来
} catch (Exception e) { e.printStackTrace(); } } }
注意,此处若没用自动关流,由于缓存区的内存没被写满,所以内容不会被写进a.txt,
1.2 缓冲字节输入流
BufferedInputStream(InputStream)
BufferedInputStream(InputStream)
BufferedInputStream(InputStream,int size) size: 缓冲区大小,默认8k
其读取数据的方法和FileInputStream是一样的(见上)
public class BufferedInputStreamDemo { public static void main(String[] args) { try ( BufferedInputStream bis = new BufferedInputStream(new FileInputStream("e:/b.txt"));// b.txt中的内容为:这个世界会好吗 ){ byte[] bs = new byte[1024]; int len ; while((len = bis.read(bs)) != -1) { //判断数据读完的条件 System.out.println(new String(bs,0,len)); } } catch (Exception e) { e.printStackTrace(); } } }
练习:使用BufferedOutputStream/BufferedInputStream拷贝文件,并比较和FileInput的拷贝性能
1 public class CopyFile { 2 public static void fileStream(String srcPath,String destPath) { 3 long start = System.currentTimeMillis(); 4 try( 5 FileInputStream fis = new FileInputStream(srcPath); 6 FileOutputStream fos = new FileOutputStream(destPath); 7 ) { 8 byte[] bs = new byte[1024]; 9 int len; 10 while((len = fis.read(bs)) != -1) { 11 fos.write(bs,0,len); 12 } 13 long end = new Date().getTime(); 14 System.out.println("字节流耗时为:"+(end-start)+"毫秒"); 15 } catch (Exception e) { 16 e.printStackTrace(); 17 } 18 } 19 public static void bufferedFileStream(String srcPath,String destPath) { 20 long start = System.currentTimeMillis(); 21 try ( 22 BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcPath)); 23 BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destPath)); 24 ){ 25 int len; 26 byte[] bs = new byte[1024]; 27 while((len = bis.read(bs)) != -1) { 28 bos.write(bs,0,len); 29 } 30 long end = new Date().getTime(); 31 System.out.println("缓冲字节流耗时为:"+(end-start)+"毫秒"); 32 } catch (Exception e) { 33 e.printStackTrace(); 34 } 35 } 36 }
运行结果是:缓冲字节流与字节流拷贝同一个文件,前者花了95毫秒,后者花了405毫秒,可见缓冲字节流效率很高
2.转换字节流
2.1 前提
转换流的本质是一种字符流,为什么叫转换流,因为其构造方法中有个字节流对象参数,相当于将字节流对象转为字符流对象
2.1.1 转换流出现的原因及思想
由于字节流操作中文不是特别的方便,所以,java就提供了转换流,其本质就是带了编码表的字节流,即:字符流=字节流+编码表
2.1.2 字符串中的编码问题
编码:把文字转为二进制
解码:把二进制转成文件
字符流只能处理纯文本文件
2.2 字符输出流
2.2.1 构造方法
(1)public OutputStreamWriter(OutputStream)
(2)public OutputStreamWriter(OutputStream out, String charsetName):此处的charsetName表示设置编码的格式,默认是utf-8
2.2.2 成员方法(用法和字节流差不多,只是这里的参数由byte数组转换为char数组,此外还可以使用String参数):
(1)public void write(int c)
(2)public void write(char[ ] cbuf)
(3)public void write(char[ ] cbuf, int len)
(4)public void write(String str)
(5)public void write(String str,int off,int len)
public class OutputStreamWriterDemo { public static void main(String[] args) { try ( OutputStreamWriter osw = new OutputStreamWriter((new FileOutputStream("e:/a.txt")),"gbk"); ){ osw.write("忽然就流出泪来,忽然间想要听到她的声音,而我却一个人越走越远"); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
2.3 字符输入流
2.3.1 构造方法
(1)public InputStreamReader(InputStream in)
(2)public InputStreamReader(InputStream in,String charsetName)
2.3.2 成员方法
(1)public int read()
(2)public int read(char[] cbuf)
public class InputStreamReaderDemo { public static void main(String[] args) { try ( InputStreamReader isr = new InputStreamReader(new FileInputStream("e:/a.txt"),"gbk"); //此处一定要用cbk编码去读取数据,因为.txt是用gbk编码格式写入的 ){ char[] chs = new char[1024]; int len; while((len = isr.read(chs)) != -1) { System.out.println(new String(chs,0,len)); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } //运行结果:忽然就流出泪来,忽然间想要听到她的声音,而我却一个人越走越远
2.4 字符流拷贝文件
public static void charFileStream(String srcPath,String destPath) { long start = System.currentTimeMillis(); try ( InputStreamReader isr = new InputStreamReader(new FileInputStream(srcPath)); OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(destPath)); ){ char[] chs = new char[1024]; int len; while((len = isr.read(chs)) != -1) { osw.write(chs,0,len); } long end = new Date().getTime(); System.out.println("字符流耗时为:"+(end-start)+"毫秒"); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } }
这里为了比较字符流拷贝文件与字节流以及缓冲字节流拷贝文件的性能,此处同时进行了这三种拷贝文件方法拷贝同一个文件的耗时比较
测试类
public class CopySpendTime { public static void main(String[] args) { CopyFile.bufferedFileStream("E:\linked.mkv", "e:/链表1.mkv"); CopyFile.fileStream("E:\linked.mkv", "e:/链表2.mkv"); CopyFile.charFileStream("E:\linked.mkv", "E:\linked1.mkv"); } }
运行结果:
3 转换流的简化写法,也叫简化流(字符流),其无法指定编码格式
3.1 读写
转换流的名字比较长,而我们常见的操作都是照本地默认编码实现的,所以,为了简化我们的书写,转换流提供了对应的子类,即FileWriter和FileReader
FileWriter:
其构造方法有很多种,这里只列出其可以传什么参数的简单构造方法,至于是否追加或是用什么编码方式的构造方法,可以直接看源码
(1)public FileWriter(String fileName)
(2)public FileWriter(File file)
public class FileWriterDemo { public static void main(String[] args) { try ( FileWriter fw = new FileWriter("e:/a.txt"); ){ fw.write("我们生来就是孤独"); } catch (IOException e) { e.printStackTrace(); } } }
FileReader:
用法类似FileWrite
public class FileReaderDemo { public static void main(String[] args) { try ( FileReader fr = new FileReader("e:/a.txt"); ){ char[] chs = new char[1024]; int len; while((len = fr.read(chs)) != -1) { System.out.println(new String(chs,0,len)); } } catch (IOException e) { e.printStackTrace(); } } }
在一个程序中先写后读,要注意:写完了以后要关流,否则输出流会继续占用文件,导致读取不回来内容
public class NoticeDemo { public static void main(String[] args) { try ( FileWriter fw = new FileWriter("e:/a.txt"); //只要执行这个语句就会创建一个a.txt文件,若加true就不会覆盖a.txt原有的内容(若有带内容的a.txt文件) FileReader fr = new FileReader("e:/a.txt"); ){ fw.write("下起了雨,你觉的冷吗"); fw.close(); //此处一定要关流,否则输出流会继续占用该文件 char[] chs = new char[1024]; int len; while((len = fr.read(chs)) != -1) { System.out.println(new String(chs,0,len)); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
3.2 简化流拷贝文件
//简化流拷贝文件 public static void SimpleStream(String srcPath, String destPath) { long start = System.currentTimeMillis(); try ( FileWriter fw = new FileWriter(destPath); FileReader fr = new FileReader(srcPath); ){ char[] chs = new char[1024]; int len; while((len = fr.read(chs)) != -1) { fw.write(chs,0,len); } long end = System.currentTimeMillis(); System.out.println("简化流耗时为:"+(end-start)+"毫秒"); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
注意srcPath和destPath地址别写反了
4. 缓冲字符流
BufferedReader/bufferedWriter
4.1 缓冲字符输出流
类似缓冲字节流,其构造方法也要传相应流的对象,不能想字符流一样传字符串
特有方法:
new Line:换行
public class BufferedWriterDemo { public static void main(String[] args) { try ( BufferedWriter bw = new BufferedWriter(new FileWriter("e:/a.txt"));//写法简单,但此种得到缓冲字符流的方法不常用 BufferedWriter bw1 = new BufferedWriter (new OutputStreamWriter(new FileOutputStream("e:/b.txt")));//很常用,因为我们得到的数据一般都为字节流,所以现将字节流包装成转换流,再讲转换流包装成缓冲字符流 ){ bw.write("这被禁忌的游戏"); bw.newLine(); //用于换行 bw.write("一如既往的岁月"); bw.flush(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
4.2 缓冲字符输入流
特有的方法:readLine 读取一行
注意:尽量不要使用readLine去拷贝文件(有可能会造成空行的丢失)
4.3 缓冲字符流拷贝文件
//缓冲字符流拷贝文件 public static void bufferedCharStream(String srcPath, String destPath) { long start = System.currentTimeMillis(); try ( // BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(destPath))); BufferedWriter bw = new BufferedWriter(new FileWriter(destPath)); // BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(srcPath))); BufferedReader br = new BufferedReader(new FileReader(srcPath)); ){ char[] chs = new char[1024]; int len; while((len = br.read(chs)) != -1) { bw.write(chs,0,len); } long end = System.currentTimeMillis(); System.out.println("缓冲字符流耗时为:"+(end-start)+"毫秒"); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }