零基础学习java------day17------缓冲字节流,转换字节流,简化流,缓冲字符流,序列化和对象流

1. 缓冲字节java

缓冲区:缓冲区实质上是一个数组。一般它是一个字节数组,可是也可使用其余种类的数组。可是一个缓冲区不 仅仅 是一个数组。缓冲区提供了对数据的结构化访问,并且还能够跟踪系统的读/写进程。数据库

缓冲流出现的缘由:使用字节流每次从文件中进行读写的时候,都须要和文件进行大量的IO交互,与磁盘交互的效率实际上是比较低的,因此为了下降与磁盘的交互次数,可使用字节缓冲流。字节缓冲流将数据放到缓存区,而缓冲区是一个内存区域的概念,咱们直接和缓冲区作交互,能够提高效率。数组

 

注意:缓存

 

(1)何时缓冲区的数据写入硬盘中?网络

     当缓冲区被写满时,或是使用flush方法将至写入硬盘(注意关流后,缓存区的内容会被写入硬盘,由于关流内部会调用flush方法)ide

2)byte数组的大小要小于缓存区,缓存区的数据是经过数组间接读入的性能

 

1.1 缓冲字节输出流测试

BufferOutputStream(OutputStream);this

 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 }
View Code

运行结果是:缓冲字节流与字节流拷贝同一个文件,前者花了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(); }
View Code

 

练习

1. 把ArrayList集合中的字符串数据存储到文本文件,要求每一个元素占一行,而后从文本文件中读取数据(每一行为一个字符串数据 )到集合中,并遍历集合

 

public class Exer1 { public static void main(String[] args) { ArrayList<String> arrayList = new ArrayList<>(); arrayList.add("热河"); arrayList.add("下雨"); arrayList.add("梵高先生"); arrayList.add("山荫路上的夏天"); ArrayList<String> array = new ArrayList<>(); try ( BufferedWriter bw = new BufferedWriter(new FileWriter("e:/a.txt")); BufferedReader br = new BufferedReader(new FileReader("e:/a.txt")); ){ //将集合总的内容写入文件a.txt
            for (String str : arrayList) { // char[] chs = str.toCharArray();
 bw.write(str); bw.newLine(); } bw.close(); // 将文件a.txt中的内容写入集合array
            String str = null; while((str = br.readLine()) != null) { array.add(str); } //遍历集合元素
            for (String arr : array) { System.out.println(arr); } } catch (IOException e) { // TODO Auto-generated catch block
 e.printStackTrace(); } } }
View Code

2. 复制单级文件夹,复制单级文件夹中指定文件并

  (1) 和原来名字保持一致

  (2)修改新的名字(使用纳秒值命名)

 

5. 序列化和对象流

 5.1 概述

  java序列化是指把java对象转换为字节序列(二进制)的过程,java反序列化是指把字节序列恢复为java对象的过程,当两个java进程进行通讯时,发送方须要把这个java对象转换为字节序列,而后在网络上传送;另外一方面,接收方须要从字节序列中恢复java的对象

  持久化:把内存数据存储到磁盘上(通常数据库)

5.2 java序列化API

(1)ObjectOutputStream:表示对象输出流

   writeObject(Object obj)方法能够对参数指定的obj对象进行序列化,把获得的字节序列写到一个目标输出流中 

(2)ObjectInputStream:表示对象输入流

   readObject()方法从输入流中读取字节序列,再把它们反序列化成为一个对象,并将其返回

5.3 java对象序列化要求

(1)假定一个Person类,它的对象须要序列化

    只有实现了Serializable或Externalizable接口的类的对象才能序列化,不然抛出异常

(2)构造方法

  ObjectOutputStream:

     public ObjectOutputStream(OutputStream out)

  ObjectInputStream:

    public ObjectInputStream(InputStream in)

(3)注意事项

  若Person类仅仅实现了Serializable接口,则能够按照如下方式进行序列化和反序列化

  ObjectOutputStream采用默认的序列化方式,对Person对象的非transient的实例变量进行序列化

  ObjectInputStream采用默认的反序列化方式,对Person对象的非transient的实例变量进行反序列化

(4)实现序列化步骤

  1. 让类实现Serializable接口

  2. 使用ObjectOutputStream写数据:调用writeObject

  3. 使用ObjectInputStream读数据:调用readObject

若是报错:NotSerializable,检查是否实现了Serializable接口

若是报错:java.io.InvalidClassException: com._51doit.javase.day17.Person; local class incompatible: stream classdesc serialVersionUID = 7515133156099803333, local class serialVersionUID = 4493040116463270318

是由模板(如Person类中重写了toString方法)改变致使的:

  解决方法:

    1. 重写一遍,而后再进行读操做

    2. 生成序列化id(此ID只是改变前的id)

        光标放到类名的黄线上,选择两个中的任意一种(这个时候再该模板后,进行读操做就不会报错)

案例

定义Person类(必定要实现Serializable接口

public class Person implements Serializable{ String name; int age; char gender; public Person(String name,int age,char gender) { this.name = name; this.age = age; this.gender = gender; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + ", gender=" + gender + "]"; } }

public class ObjectOutputStreamDemo { public static void main(String[] args) { Person p = new Person("老王",38,''); try ( ObjectOutputStream oot = new ObjectOutputStream(new FileOutputStream("e:/a.txt")); ){ oot.writeObject(p);
       oot.writeInt(100); //此处要注意写入的顺序,这里是先写p,再写的100,读的时候也要按照这个顺序读 oot.flush(); }
catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }

将内容读出来

public class ObjectInputStreamDemo { public static void main(String[] args) { try ( ObjectInputStream ois = new ObjectInputStream(new FileInputStream("e:/a.txt")); ){ Object o = ois.readObject();
       ois.readIn(); // 此处若将这一行和上一行换个顺序,将会出现java.io.EOFException错误,由于写入文件的内容是先p,再100 Person p
= (Person)o; System.out.println(p.name+p.age+p.gender); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }

运行结果:老王38男

 

练习:使用对象流写一个person对象,再写一个Map<Integer,Person>

相关文章
相关标签/搜索