Java I/O流总结(二)

来源:互联网 发布:cad of mac中文破解版 编辑:程序博客网 时间:2024/03/29 09:48
/*@author StormWangxhu@date 2017/11/1*/
面对压力,我可以挑灯夜战,不眠不休。面对挑战,我愿意迎难而上,永不退缩!

昨天我们总结了字符的输入流,主要进行读写的功能。今天来看一下字节流InputStreamOutputStream.

字节流基本框架体系图

整体体系:
这里写图片描述
InputStream:
这里写图片描述

基本概念

和字符流一样,字节流也有两个抽象基类作为其他类的父类。一个是InputStream,一个是OutPutStream.其他的类都是这两个类的拓展类。

(1)特点:
字节流可以操作任何数据。
(2)注意:
字节流使用的是字节数组 byte[]
字符流使用得是字符数组 char[]

  • inputStream
    (1)、inputStream是所有字节输入流的父类,是一个抽象类。
    (2)ByteArrayInputStream、StringBufferInputStream、FileInputStream 是三种基本的介质流,它们分别从Byte 数组、StringBuffer、和本地文件中读取数据。
    (3)ObjectInputStream 和所有FilterInputStream 的子类都是装饰流(装饰器模式的主角)。
  • outputStream
    (1)、OutputStream 是所有的输出字节流的父类,它是一个抽象类。
    (2)、B
    yteArrayOutputStream、FileOutputStream 是两种基本的介质流,它们分别向Byte 数组、和本地文件中写入数据。PipedOutputStream 是向与其它线程共用的管道中写入数据。
    (3)、ObjectOutputStream 和所有FilterOutputStream 的子类都是装饰流。
  • 其他

(1)、LineNumberInputStream 主要完成从流中读取数据时,会得到相应的行号,至于什么时候分行、在哪里分行是由改类主动确定的,并不是在原始中有这样一个行号。在输出部分没有对应的部 分,我们完全可以自己建立一个LineNumberOutputStream,在最初写入时会有一个基准的行号,以后每次遇到换行时会在下一行添加一个行 号,看起来也是可以的。好像更不入流了。
(2)、PushbackInputStream 的功能是查看最后一个字节,不满意就放入缓冲区。主要用在编译器的语法、词法分析部分。输出部分的BufferedOutputStream 几乎实现相近的功能。
StringBufferInputStream 已经被Deprecated,本身就不应该出现在InputStream 部分,主要因为String 应该属于字符流的范围。已经被废弃了,当然输出部分也没有必要需要它了!还允许它存在只是为了保持版本的向下兼容而已。
(3)、SequenceInputStream 可以认为是一个工具类,将两个或者多个输入流当成一个输入流依次读取。完全可以从IO 包中去除,还完全不影响IO 包的结构,却让其更“纯洁”――纯洁的Decorator 模式。
(4)、PrintStream 也可以认为是一个辅助工具。主要可以向其他输出流,或者FileInputStream 写入数据,本身内部实现还是带缓冲的。本质上是对其它流的综合运用的一个工具而已。一样可以踢出IO 包!System.out 和System.out 就是PrintStream 的实例!


下面我们通过案例来分别讲解一下这些字节流的使用。首先讲解一下FileInputStream:

案例一:利用字节流读取或写入文本内容到控制台或者文本文件中

package com.StormWang.InputStream;import java.io.FileInputStream;import java.io.FileWriter;import java.io.IOException;/*** @author StormWangxhu* @version 创建时间:2017年11月1日 上午11:19:03**/ class FileInStream{     //读文件,一个一个的读,读一个存一个     public static void readFile_1(){         //先写一个文件         FileWriter fileWriter = null ;         FileInputStream fileInputStream = null ;         try {             fileWriter = new FileWriter("input.txt");             fileWriter.write("FileInputStream,success.");             fileWriter.flush();             fileInputStream = new FileInputStream("input.txt");             int ch = 0 ;             while ((ch= fileInputStream.read())!=-1) {                System.out.print((char)ch);            }        } catch (Exception e) {            // TODO: handle exception            e.printStackTrace();        }finally {            if (fileInputStream != null) {                try {                    fileInputStream.close();                } catch (Exception e2) {                    // TODO: handle exception                    e2.printStackTrace();                }            }            if (fileWriter != null) {                try {                    fileWriter.close();                } catch (Exception e2) {                    // TODO: handle exception                    e2.printStackTrace();                }            }        }     }     /*     //读方法二(读完之后,一起存起来。)     public static void readFile_2() {         FileInputStream fileInputStream = null ;         try {            fileInputStream = new FileInputStream("E:\\eclipse-workspace\\day1101\\input.txt");            byte[] buf = new byte[1024];            int len = 0 ;            while ((len = fileInputStream.read()) != -1) {                System.out.println("len是:"+len);                //System.out.print(new String(buf,0,len));                System.out.println(buf);            }            System.out.println("buf数组内容:"+buf);        } catch (IOException e) {            e.printStackTrace();        }finally {            if (fileInputStream != null) {                try {                    fileInputStream.close();                } catch (Exception e2) {                    // TODO: handle exception                    System.out.println("close:"+e2.toString());                }            }        }     }*/    }public class FileInputStreamDemo {    public static void main(String[] args) {        FileInStream fileInStream = new FileInStream() ;        fileInStream.readFile_1();    }}

我们来看一下结果:
这里写图片描述


再来看一个实例:实现对一个图片文件的复制
案例二:

package com.StormWang.InputStream;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;/*** @author StormWangxhu* @version 创建时间:2017年11月1日 下午4:53:32**/public class CopyPicture {    /*     * 实现功能:  实现图片文件的复制     * 思路:     * 1、字节输入流和图片文件相关联     * 2、再用字节输入流将图片文件数据写入到缓冲区中,即字节数组中     * 3、通过循环读写,完成数据的存储     * 4、关闭流资源。     * */    public static void main(String[] args) {        // TODO Auto-generated method stub        FileInputStream  fileInputStream = null;        FileOutputStream fileOutputStream =null ;        try {            fileInputStream = new FileInputStream("F:\\2016\\1.jpg");            //测试代码            System.out.println("已过!");            fileOutputStream = new FileOutputStream("F:\\2.JPG");            byte[] buff = new byte[1024];            int ch =  0 ;            //此处的read()方法可能会抛出IOException异常,我们catch一下。            while ((ch= fileInputStream.read(buff)) !=-1) {                /*                 *write方法说明:                 *write(byte[] b, int off, int len)                  *      将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此文件输出流。                  *                  * */                fileOutputStream.write(buff, 0, ch);            }        } catch (FileNotFoundException e) {            // TODO Auto-generated catch block            e.printStackTrace();        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }finally {            if (fileInputStream != null) {                try {                    fileInputStream.close();                } catch (IOException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }            }            if (fileOutputStream != null) {                try {                    fileOutputStream.close();                } catch (IOException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }            }        }    }}
问题:在输入流和图片文件关联时,系统找不到指定文件。

这里写图片描述

F盘文件如下所示,不知道为什么会找不到文件呢?待解决:。。。。。。。

这里写图片描述

自定义缓冲字节流

package com.StormWang.InputStream;/*** @author StormWangxhu* @version 创建时间:2017年11月1日 下午6:44:40**/import java.io.IOException;import java.io.InputStream;public class MyBuffereedInputStream {    private InputStream iStream ;    private byte[] buff = new byte[1024];    private int pos = 0,count = 0 ;    public MyBuffereedInputStream(InputStream iStream) {        // TODO Auto-generated constructor stub        this.iStream = iStream ;    }    public int myRead() throws IOException{        //通过iStream读取硬盘中的数据,存储到buff        //如果count=0,说明byte数组是空的,所以开始读取数据        if (count == 0) {            count = iStream.read(buff);            //标记位            pos = 0;            //通过下标找到数组            byte bt = buff[pos];            //byte数组个数递减            count--;            //移动标记位            pos++;            return bt&255;        }        //如果字节数组中还有数据,则继续往出取        else if (count>0) {            byte bt = buff[pos];            count--;            pos++;            return bt & 255 ;        }        return -1 ;    }    //关闭流方法    public void myClose() {        try {            iStream.close();        } catch (IOException e) {            e.printStackTrace();        }    }}

这样就完成了自定义字节流的定义。下面我们来应用一下:

package com.StormWang.InputStream;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.OutputStream;/*** @author StormWangxhu* @version 创建时间:2017年11月1日 下午7:08:36**/public class myBufferedInputStreamTest {    public static void main(String[] args) {        // TODO Auto-generated method stub        FileInputStream fInStream = null;        MyBuffereedInputStream myBuffereedInputStream = null ;        BufferedOutputStream bufferedOutputStream = null;        try {            fInStream = new FileInputStream("E:\\eclipse-workspace\\day1101\\src\\com\\StormWang\\InputStream\\CopyPicture.java");            myBuffereedInputStream = new MyBuffereedInputStream(fInStream);            bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("myBuff.txt"));            int ch = 0;            while ((ch=myBuffereedInputStream.myRead())!= -1) {                bufferedOutputStream.write(ch);            }        } catch (FileNotFoundException e) {            // TODO Auto-generated catch block            e.printStackTrace();        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }finally {            if (myBuffereedInputStream!= null) {                myBuffereedInputStream.myClose();            }            if (bufferedOutputStream != null) {                try {                    bufferedOutputStream.close();                } catch (IOException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }            }            if (fInStream != null) {                try {                    fInStream.close();                } catch (IOException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }            }        }    }}

我们来看一下结果:
这里写图片描述
读写成功!

(待回头再思考。。。。。。)**注意:**字节流的read()方法读取一个字节。为什么返回的不是byte类型的,而是int 类型的呢?因为read方法读到末尾时返回的是-1.而在所操作的数据中的很容易出现连续多个1的情况,而连续读到81,就是-1.导致读取会提前停止。所以将读到的一个字节给提升为一个int类型的数值,但是只保留原字节,并在剩余二进制位补0.具体操作是:byte&255  or  byte&0xff    对于write方法,可以一次写入一个字节,但接收的是一个int类型数值。只写入该int类型的数值的最低一个字节(8位)。即对于write()方法实际上进行了强制转化的动作。简单说:read方法对读到的数据进行提升。write对操作的数据进行转换。**

转换流

  • 特点:
    1,是字节流和字符流之间的桥梁。
    2,该流对象中可以对读取到的字节数据进行指定编码表的编码转换。
  • 什么时候使用呢?
    1,当字节和字符之间有转换动作时。
    2,流操作的数据需要进行编码表的指定时。
    具体的对象体现:这两个流对象是字符流体系中的成员。
    1,InputStreamReader:字节到字符的桥梁。
    2,OutputStreamWriter:字符到字节的桥梁。
    这两个流对象是字符流体系中的成员。那么它们有转换作用,而本身又是字符流。所以在构造的时候,需要传入字节流对象进来。
    构造函数:
    InputStreamReader(InputStream):通过该构造函数初始化,使用的是本系统默认的编码表GBK。
    InputStreamReader(InputStream,StringcharSet):通过该构造函数初始化,可以指定编码表。
    OutputStreamWriter(OutputStream):通过该构造函数初始化,使用的是本系统默认的编码表GBK。
    OutputStreamWriter(OutputStream,StringcharSet):通过该构造函数初始化,可以指定编码表。
我们来看看API是怎么解释的:

这里写图片描述
我们通过代码来演示一下:

小技巧:1.  *   源:键盘录入  *   目的:控制台  * @author StormWangxhu  * 2.改变需求:想把键盘录入的数据存储到一个文件中  *   源:键盘  *   目的:文件  *     * 3.改变需求:想要将一个文件数据打印到控制台上  *   源:文件  *   目的:控制台  *     *   ######################流操作的基本规律:##############  *     最痛苦的就是流对象有很多,不知道该用哪一个?                                      *      通过三个明确来完成:                                                              *        1.明确源和目的                                                             *           源:输入流.    InputStream    Reader                                                    *          目的:输出流.   OutputStream    Writer                                                        *        2.明确操作的数据是否是是纯文本     *           是纯文本:用字符流  *         不是纯文本:用字节流      *        3.当体系明确后,再明确要使用哪个具体的对象  *           通过设备来进行区分:  *              源设备:内存、硬盘、键盘  *            目的设备:内存、硬盘(文件)、控制台              *   ----------------------3个需求之一-----------------------    *     1.将一个文本文件中的数据存储到另一个文件中  ,也就是复制文件  *          源:因为是源,所以使用读取流:InputStream     Reader  *              a.是不是操作文本文件?  *                   是:这就可以选择Reader  *                 不是:可以选择InputStream  *             这样下来,所属体系就明确了。  *               *             b.接下来就要明确要使用体系中的哪个对象?  *               明确设备:硬盘上的一个文件  *               Reader体系中可以操作文件的对象是FileReader  *             c.是否需要提高效率?  *                需要:加入Reader体系的缓区:BufferedReader  *                 *       接下来就是: *  1) FileReader  fr =new FileReader("a.txt");             2) BufferedReader br = new BufferedReader(fr);  *       目的:文件 OutputStream    Writer  *             a.目的是否是纯文本的?  *                是:Writer  *              不是:OutputStream   *             b.明确设备:硬盘上的一个文件  *                Writer体系中可以操作一个文件的对象是FileWriter  *                  *             c.是否需要提高效率?  *                 需要:加入Writer体系的缓冲区:BufferedWriter  *               *       接下来就是:  * 1) FileWriter fw = new FileWriter("b.txt");     2) BufferedWriter bw = new BufferedWriter(fw);   *                   *     练习: 将一个图片文件中的数据存储到另一个图片中 ,即为copy图片,要按照以上的格式去写                                         *          源(是图片):因为是源, 所以使用读取流:InputStream    Reader  *                a.是不是操作的纯文本文件?  *                 不是:这就可以选择InputStream  *                   是:这就可以选择 Reader     *                b.接下来就要明确要使用体系中的哪个对象?     *                   明确设备:硬盘上的一个图片  *                   InputStream体系中可以操作图片的对象时FileInputStream  *                c.是否需要提高效率?  *                   *  需要:加入InputStream体系的缓冲区:BufferedInputStream  *          *         接下来就是: * FileInputStream fis = new FileInputStream("1.jpg");  BufferedInputStream bis = new BufferedInputStream(fis);  *                目的:文件  OutputStream      Writer  *                 a.是否是纯文本的文件?  *                    不是:OutputStream   *                      是:writer  *                 b.明确设备:硬盘上的一个图片  *                   *    OutputStream体系中可以操作一个文件的对FileOutputStream  *                 c.是否需要提高效率?  *                 *  需要:加入OutputStream体系的缓冲区:BufferedOutputStream      *                                                  FileOutputStream fos = new FileOutputStream("2.jpg");  *                      *  BufferedOutputStream bos =  BufferedOutputStream(fos);                                          *                              
我们来实现一个功能,把一个 文件的内容 输出到 控制台 上
package com.StormWang.InputStream;import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.FileWriter;import java.io.IOException;import java.io.InputStreamReader;import java.io.OutputStreamWriter;/*** @author StormWangxhu* @version 创建时间:2017年11月1日 下午8:04:29**//* * 实现将一个文件中的内容输出到控制台上 * */public class FileStreamDemo_2 {    public static void main(String[] args) {        // TODO Auto-generated method stub        //创建读取和写入对象        BufferedReader bReader =  null ;        BufferedWriter bWriter = null ;        try {            /**             * FileinputStream fs = new FileInutStream("E:\\eclipse-workspace\\day1101\\myBuff.txt");             * InputStreamReader isr = new InputStreamReader(fs);             * BufferedReader br = new BufferedReader(isr);             * 以上三句合并为一句如下:             */            bReader = new BufferedReader(                    new InputStreamReader(//将字节流转换为字符流。                            new FileInputStream("E:\\eclipse-workspace\\day1101\\myBuff.txt")));            bWriter = new BufferedWriter(                    //将字符流转化为字节流                    //并输出到控制台上                    new OutputStreamWriter(System.out));            //循环读取            String lines = null ;            /**             * readLine()方法的原理:             *  其实缓冲区中的readLine()方法,用的还是与缓冲区关联的流对象的read()方法 。             *  只不过,每一次读到一个字符,先不进行具体的操作,先进行临时存储。             *  当读到回车标记时,将临时容器中存储的数据一次性的返回。             *              * */            while ((lines =  bReader.readLine())!= null) {                //读一行,写一行,把每一行都写到输出流中                bWriter.write(lines);                //写一行后换一行                //newLine()方法为跨平台换行。。                bWriter.newLine();                //写一行刷新一行                bWriter.flush();            }        } catch (FileNotFoundException e) {            System.out.println("找不到文件了!");            e.printStackTrace();        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }finally {            if (bReader!= null) {                try {                    bReader.close();                }catch (Exception e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }                if (bWriter!= null) {                    try {                        bWriter.close();                    } catch (IOException e) {                        // TODO Auto-generated catch block                        e.printStackTrace();                    }                }            }        }    }}

看一下结果:
这里写图片描述
输出成功!

好了,就先总结到这儿吧。如有错误,还望指正!
原创粉丝点击