Java I/O流总结(二)

本文详细介绍了Java IO字节流的基本概念、体系结构及常用类的使用方法,包括FileInputStream、FileOutputStream等,通过实例展示了如何进行文件的读写操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/*
@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();
                    }
                }
            }
        }
    }

}

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

好了,就先总结到这儿吧。如有错误,还望指正!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值