博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
IO流理解——传统的BIO
阅读量:4298 次
发布时间:2019-05-27

本文共 16730 字,大约阅读时间需要 55 分钟。

目录

 

 

 

 

 


1.概述——什么是流

流类似于传输的媒介,Java程序运行在jvm中,jvm需要把数据存到磁盘,或者是jvm将数据通过网络传输传到另一个主机的jvm中,需要先建立流这个通道,流通道连接了传输起点与传输目的地。这就决定了流对象的构造方法中路径是一个主要的属性。

2.流的分类

  • 根据处理数据类型的不同分为:字符流和字节流
  • 根据数据流向不同分为:输入流和输出流

3.字符流和字节流的区别

字符流的由来: 因为数据编码的不同,而有了对字符进行高效操作的流对象。本质其实就是基于字节流读取时,去查了指定的码表(可以设置)。 字节流和字符流的区别:

  • 读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。
  • 处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。

  • 字节流:一次读入或读出是8位二进制。
  • 字符流:一次读入或读出是16位二进制。

设备上的数据无论是图片或者视频,文字,它们都以二进制存储的。二进制的最终都是以一个8位为数据单元进行体现,所以计算机中的最小数据单元就是字节。意味着,字节流可以处理设备上的所有数据,所以字节流一样可以处理字符数据。字符流多了一步处理流程,把二进制文件读出来进行字符转换,直接得到字符值,而字节流需要处理后才可以看到可读性结果。

结论:只要是处理纯文本数据,就优先考虑使用字符流。 除此之外都使用字节流。

更详细解释

4.继承关系图

这里写图片描述

这里写图片描述

 

这里写图片描述

 

这里写图片描述

5.编程入门

读取文件内容

package com.app;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.IOException;public class A1 {    public static void main(String[] args) {        A1 a1 = new A1();            //电脑d盘中的abc.txt 文档        String filePath = "D:/abc.txt" ;        String reslut = a1.readFile( filePath ) ;        System.out.println( reslut );     }    /**     * 读取指定文件的内容     * @param filePath : 文件的路径     * @return  返回的结果     */    public String readFile( String filePath ){        FileInputStream fis=null;        String result = "" ;        try {            // 根据path路径实例化一个输入流的对象            fis  = new FileInputStream( filePath );            //2. 返回这个输入流中可以被读的剩下的bytes字节的估计值;            int size =  fis.available() ;            //3. 根据输入流中的字节数创建byte数组;            byte[] array = new byte[size];            //4.把数据读取到数组中;            fis.read( array ) ;             //5.根据获取到的Byte数组新建一个字符串,然后输出;            result = new String(array);         } catch (FileNotFoundException e) {            e.printStackTrace();        }catch (IOException e) {            e.printStackTrace();        }finally{            if ( fis != null) {                try {                    fis.close();                } catch (IOException e) {                    e.printStackTrace();                }            }        }        return result ;    }}

 

将内容写入文件

package com.app;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;public class A2 {    public static void main(String[] args) {        A2 a2 = new A2();        //电脑d盘中的abc.txt 文档        String filePath = "D:/abc.txt" ;        //要写入的内容        String content = "今天是2017/1/9,天气很好" ;        a2.writeFile( filePath , content  ) ;    }    /**     * 根据文件路径创建输出流     * @param filePath : 文件的路径     * @param content : 需要写入的内容     */    public void writeFile( String filePath , String content ){        FileOutputStream fos = null ;        try {            //1、根据文件路径创建输出流            fos  = new FileOutputStream( filePath );            //2、把string转换为byte数组;            byte[] array = content.getBytes() ;            //3、把byte数组输出;            fos.write( array );        } catch (FileNotFoundException e) {            e.printStackTrace();        }catch (IOException e) {            e.printStackTrace();        }finally{            if ( fos != null) {                try {                    fos.close();                } catch (IOException e) {                    e.printStackTrace();                }            }        }    }}

 

实现复制文件,从D盘复制到E盘

package com.app;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;public class A3 {    public static void main(String[] args) {        A3 a2 = new A3();        //电脑d盘中的cat.png 图片的路径        String filePath1 = "D:/cat.png" ;        //电脑e盘中的cat.png 图片的路径        String filePath2 = "E:/cat.png" ;        //复制文件        a2.copyFile( filePath1 , filePath2 );    }    /**     * 文件复制      * @param filePath_old : 需要复制文件的路径     * @param filePath_new : 复制文件存放的路径     */    public void copyFile( String filePath_old  , String filePath_new){        FileInputStream fis=null ;        FileOutputStream fout = null ;        try {            // 根据path路径实例化一个输入流的对象            fis  = new FileInputStream( filePath_old );            //2. 返回这个输入流中可以被读的剩下的bytes字节的估计值;            int size =  fis.available() ;            //3. 根据输入流中的字节数创建byte数组;            byte[] array = new byte[size];            //4.把数据读取到数组中;            fis.read( array ) ;             //5、根据文件路径创建输出流            fout = new FileOutputStream( filePath_new ) ;                        //5、把byte数组输出;            fout.write( array );        } catch (FileNotFoundException e) {            e.printStackTrace();        }catch (IOException e) {            e.printStackTrace();        }finally{            if ( fis != null) {                try {                    fis.close();                } catch (IOException e) {                    e.printStackTrace();                }            }            if ( fout != null ) {                try {                    fout.close();                } catch (IOException e) {                    e.printStackTrace();                }               }        }    }}

6.缓冲流-BufferedInputStream、BufferedOutputStream

首先抛出一个问题,有了InputStream为什么还要有BufferedInputStream?

BufferedInputStreamBufferedOutputStream这两个类分别是FilterInputStreamFilterOutputStream的子类,作为装饰器子类,使用它们可以防止每次读取/发送数据时进行实际的写操作,代表着使用缓冲区。

我们有必要知道不带缓冲的操作,每读一个字节就要写入一个字节,由于涉及磁盘的IO操作相比内存的操作要慢很多,所以不带缓冲的流效率很低。带缓冲的流,可以一次读很多字节,但不向磁盘中写入,只是先放到内存里。等凑够了缓冲区大小的时候一次性写入磁盘,这种方式可以减少磁盘操作次数,速度就会提高很多!

同时正因为它们实现了缓冲功能,所以要注意在使用BufferedOutputStream写完数据后,要调用flush()方法或close()方法,强行将缓冲区中的数据写出。否则可能无法写出数据。与之相似还BufferedReaderBufferedWriter两个类。

现在就可以回答在本文的开头提出的问题:

BufferedInputStreamBufferedOutputStream类就是实现了缓冲功能的输入流/输出流。使用带缓冲的输入输出流,效率更高,速度更快。

总结:

  • BufferedInputStream 是缓冲输入流。它继承于FilterInputStream

  • BufferedInputStream 的作用是为另一个输入流添加一些功能,例如,提供“缓冲功能”以及支持mark()标记reset()重置方法

  • BufferedInputStream 本质上是通过一个内部缓冲区数组实现的。例如,在新建某输入流对应的BufferedInputStream后,当我们通过read()读取输入流的数据时,BufferedInputStream会将该输入流的数据分批的填入到缓冲区中。每当缓冲区中的数据被读完之后,输入流会再次填充数据缓冲区;如此反复,直到我们读完输入流数据位置。

实战演练1:复制文件.

package com.app;import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;public class A3 {    public static void main(String[] args) throws IOException {        String filePath = "F:/123.png" ;        String filePath2 = "F:/abc.png" ;        File file = new File( filePath ) ;        File file2 = new File( filePath2 ) ;        copyFile( file , file2 );    }        /**     * 复制文件     * @param oldFile     * @param newFile     */    public static void copyFile( File oldFile , File newFile){        InputStream inputStream = null ;        BufferedInputStream bufferedInputStream = null ;        OutputStream outputStream = null ;        BufferedOutputStream bufferedOutputStream = null ;        try {            inputStream = new FileInputStream( oldFile ) ;            bufferedInputStream = new BufferedInputStream( inputStream ) ;            outputStream = new FileOutputStream( newFile ) ;            bufferedOutputStream = new BufferedOutputStream( outputStream ) ;            byte[] b=new byte[1024];   //代表一次最多读取1KB的内容            int length = 0 ; //代表实际读取的字节数            while( (length = bufferedInputStream.read( b ) )!= -1 ){                //length 代表实际读取的字节数                bufferedOutputStream.write(b, 0, length );            }            //缓冲区的内容写入到文件            bufferedOutputStream.flush();        } catch (FileNotFoundException e) {            e.printStackTrace();        }catch (IOException e) {            e.printStackTrace();        }finally {            if( bufferedOutputStream != null ){                try {                    bufferedOutputStream.close();                } catch (IOException e) {                    e.printStackTrace();                }            }            if( bufferedInputStream != null){                try {                    bufferedInputStream.close();                } catch (IOException e) {                    e.printStackTrace();                }            }                        if( inputStream != null ){                try {                    inputStream.close();                } catch (IOException e) {                    e.printStackTrace();                }            }                        if ( outputStream != null ) {                try {                    outputStream.close();                } catch (IOException e) {                    e.printStackTrace();                }            }        }    }}

 

那么什么时候flush()才有效呢?

答案是:当OutputStream是BufferedOutputStream时。

当写文件需要flush()的效果时,需要

FileOutputStream fos = new FileOutputStream("c:\a.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos);
也就是说,需要将FileOutputStream作为BufferedOutputStream构造函数的参数传入,然后对BufferedOutputStream进行写入操作,才能利用缓冲及flush()。

查看BufferedOutputStream的源代码,发现所谓的buffer其实就是一个byte[]。

BufferedOutputStream的每一次write其实是将内容写入byte[],当buffer容量到达上限时,会触发真正的磁盘写入。
而另一种触发磁盘写入的办法就是调用flush()了。

1.BufferedOutputStreamclose()时会自动flush

2.BufferedOutputStream在不调用close()的情况下,缓冲区不满,又需要把缓冲区的内容写入到文件或通过网络发送到别的机器时,才需要调用flush.

7.缓冲流-BufferedReader、BufferedWriter

实战演练——复制F盘里面的一个txt文本

package com.app;import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.File;import java.io.FileNotFoundException;import java.io.FileReader;import java.io.FileWriter;import java.io.IOException;import java.io.Reader;import java.io.Writer;public class A4 {    public static void main(String[] args) {        String filePath = "F:/123.txt" ;        String filePath2 = "F:/abc.txt" ;        File file = new File( filePath ) ;        File file2 = new File( filePath2 ) ;        copyFile( file , file2 );    }    private static void copyFile( File oldFile , File newFile ){        Reader reader = null ;        BufferedReader bufferedReader = null ;        Writer writer = null ;        BufferedWriter bufferedWriter  = null ;        try {            reader = new FileReader( oldFile ) ;            bufferedReader = new BufferedReader( reader ) ;            writer = new FileWriter( newFile ) ;            bufferedWriter = new BufferedWriter( writer ) ;            String result = null ; //每次读取一行的内容            while (  (result = bufferedReader.readLine() ) != null ){                bufferedWriter.write( result );  //把内容写入文件                bufferedWriter.newLine();  //换行,result 是一行数据,所以没写一行就要换行             }            bufferedWriter.flush();  //强制把数组内容写入文件        } catch (FileNotFoundException e) {            e.printStackTrace();        }catch (IOException e) {            e.printStackTrace();        }finally {            try {                bufferedWriter.close();  //关闭输出流            } catch (IOException e) {                e.printStackTrace();            }            try {                bufferedReader.close();  //关闭输入流            } catch (IOException e) {                e.printStackTrace();            }        }    }}

 

8.转换流-InputStreamReader、OutputStreamWriter

实战演练,复制文本

package com.app;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStream;import java.io.OutputStreamWriter;public class A5 {    public static void main(String[] args) {        String filePath = "F:/123.txt" ;        String filePath2 = "F:/abc.txt" ;        File file = new File( filePath ) ;        File file2 = new File( filePath2 ) ;        copyFile( file , file2 );    }    private static void copyFile( File oldFile , File newFile ){        InputStream inputStream = null ;        InputStreamReader inputStreamReader = null ;        OutputStream outputStream = null ;        OutputStreamWriter outputStreamWriter = null ;        try {            inputStream = new FileInputStream( oldFile ) ; //创建输入流            inputStreamReader = new InputStreamReader( inputStream ) ; //创建转换输入流            outputStream = new FileOutputStream( newFile ) ; //创建输出流            outputStreamWriter = new OutputStreamWriter( outputStream ) ; //创建转换输出流            int result = 0 ;            while( (result = inputStreamReader.read()) != -1){  //一次只读一个字符                outputStreamWriter.write( result ); //一次只写一个字符            }            outputStreamWriter.flush();  //强制把缓冲写入文件        } catch (FileNotFoundException e) {            e.printStackTrace();        }catch (IOException e) {            e.printStackTrace();        }finally{            if ( outputStreamWriter != null) {                try {                    outputStreamWriter.close();                } catch (IOException e) {                    e.printStackTrace();                }            }            if ( inputStreamReader != null ) {                try {                    inputStreamReader.close();                } catch (IOException e) {                    e.printStackTrace();                }            }        }    }}

9.ByteArrayInputStream、ByteArrayOutputStream

练习1 字节流ByteArrayInputStream的读写过程测试

package com.app;import java.io.ByteArrayInputStream;import java.io.IOException;public class A7 {        public static void main(String[] args) {                String mes = "hello,world" ;        byte[] b = mes.getBytes() ;                ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( b ) ;        int result = -1  ;        while( ( result = byteArrayInputStream.read() ) != -1){            System.out.println( (char) result );        }                try {            byteArrayInputStream.close();        } catch (IOException e) {            e.printStackTrace();        }    }}

练习2ByteArrayOutputStream读出的字节流用FileOutputStream写入文件

package com.app;import java.io.ByteArrayOutputStream;import java.io.File;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;public class A6 {    public static void main(String[] args) {        String mes = "你好,world" ;        byte[] b = mes.getBytes() ;        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream() ;        try {            byteArrayOutputStream.write( b );            FileOutputStream fileOutputStream = new FileOutputStream( new File( "F:/123.txt" ) ) ;            byteArrayOutputStream.writeTo( fileOutputStream ) ;            fileOutputStream.flush();        } catch (FileNotFoundException e) {            e.printStackTrace();        }catch (IOException e) {            e.printStackTrace();        }finally{            try {                byteArrayOutputStream.close();            } catch (IOException e) {                e.printStackTrace();            }        }    }}

10.ObjectOutputStream序列化与ObjectInputStream反序列化

为了演示序列化在Java中是怎样工作的,我将使用之前教程中提到的Employee类,假设我们定义了如下的Employee类,该类实现了Serializable 接口。

public class Employee implements java.io.Serializable{   public String name;   public String address;   public transient int SSN;   public int number;   public void mailCheck()   {      System.out.println("Mailing a check to " + name                           + " " + address);   }}

 

序列化对象

ObjectOutputStream 类用来序列化一个对象,如下的 SerializeDemo 例子实例化了一个 Employee 对象,并将该对象序列化到一个文件中。

该程序执行后,就创建了一个名为 employee.ser 文件。该程序没有任何输出,但是你可以通过代码研读来理解程序的作用。

注意: 当序列化一个对象到文件时, 按照 Java 的标准约定是给文件一个 .ser 扩展名。

public class SerializeDemo{   public static void main(String [] args)   {      Employee e = new Employee();      e.name = "Reyan Ali";      e.address = "Phokka Kuan, Ambehta Peer";      e.SSN = 11122333;      e.number = 101;      try      {         FileOutputStream fileOut =         new FileOutputStream("/tmp/employee.ser");         ObjectOutputStream out = new ObjectOutputStream(fileOut);         out.writeObject(e);         out.close();         fileOut.close();         System.out.printf("Serialized data is saved in /tmp/employee.ser");      }catch(IOException i)      {          i.printStackTrace();      }   }}

 

反序列化对象

下面的 DeserializeDemo 程序实例了反序列化,/tmp/employee.ser 存储了 Employee 对象。

public class DeserializeDemo{   public static void main(String [] args)   {      Employee e = null;      try      {         FileInputStream fileIn = new FileInputStream("/tmp/employee.ser");         ObjectInputStream in = new ObjectInputStream(fileIn);         e = (Employee) in.readObject();         in.close();         fileIn.close();      }catch(IOException i)      {         i.printStackTrace();         return;      }catch(ClassNotFoundException c)      {         System.out.println("Employee class not found");         c.printStackTrace();         return;      }      System.out.println("Deserialized Employee...");      System.out.println("Name: " + e.name);      System.out.println("Address: " + e.address);      System.out.println("SSN: " + e.SSN);      System.out.println("Number: " + e.number);    }}

 

以上程序编译运行结果如下所示:

Deserialized Employee...Name: Reyan AliAddress:Phokka Kuan, Ambehta PeerSSN: 0Number:101

 

你可能感兴趣的文章
Xcode 的正确打开方式——Debugging
查看>>
打包app出现的一个问题
查看>>
iOS在Xcode6中怎么创建OC category文件
查看>>
Expanding User-Defined Runtime Attributes in Xcode with Objective-C
查看>>
iOS7 UITabBar自定义选中图片显示为默认蓝色的Bug
查看>>
提升UITableView性能-复杂页面的优化
查看>>
25 iOS App Performance Tips & Tricks
查看>>
那些好用的iOS开发工具
查看>>
iOS最佳实践
查看>>
使用CFStringTransform将汉字转换为拼音
查看>>
更轻量的 View Controllers
查看>>
Chisel-LLDB命令插件,让调试更Easy
查看>>
时间格式化hh:mm:ss和HH:mm:ss区别
查看>>
When to use Delegation, Notification, or Observation in iOS
查看>>
Objective-C Autorelease Pool 的实现原理
查看>>
编程语言大牛王垠:编程的智慧,带你少走弯路
查看>>
ios指令集以及基于指令集的app包压缩策略
查看>>
iOS开发者的福利 — — iOS9+Xcode7免越狱免证书直接调试
查看>>
3、JavaWeb学习之基础篇—JSP
查看>>
4、JavaWeb学习之基础篇—Session
查看>>