zoukankan      html  css  js  c++  java
  • Java IO流详解(三)——字节流InputStream和OutPutStream

           我们都知道在计算机中,无论是文本、图片、音频还是视频,所有的文件都是以二进制(字节)形式存在的,IO流中针对字节的输入输出提供了一系列的流,统称为字节流。字节流是程序中最常用的流。在JDK中,提供了两个抽象类InputStream和OutputStream,它们是字节流的顶级父类,所有的字节输入流都继承自InputStream,所有的字节输出流都继承自OutputStream。既然二者是抽象类,那么就不能实例化,都是依赖于具体继承它们的子类去实现。但二者抽象类中也包含它们各自的方法,如果我们先了解清楚抽象类中每一个方法的含义,那么对于后续具体的子类将会有非常大的帮助。

    1、字节输入流InputStream

        InputStream是所有字节输入流的父类,定义了所有字节输入流都具有的共同特征。其内部提供的方法如下:

    image

       上图中重载的三个read()方法都是用来读数据的。

    • int read():每次读取一个字节,返回读取到的字节。
    • int read(byte[] b):每次读取 b 数组长度的字节数,然后返回读取的字节,读到末尾时返回-1。
    • int read(byte[] b,int off,int len):每次读取 b 数组长度的字节数,从数组b 的索引为off 的位置开始,长度为len个字节。

    其中InputStream的子类FileInputStream是专门用于读取文件中的数据,通过它将目标设备上的数据读入到程序。

      FileInputStream读入文件举例(读取的hello.txt文件内容是 ABCDEFGH):

    package com.thr;
    
    import java.io.*;
    
    /**
     * @author Administrator
     * @date 2020-02-21
     * @desc 字节输入流FileInputStream
     */
    public class FileInputStreamTest {
    
        public static void main(String[] args)  {
            //定义输入流
            FileInputStream fis =null;
            try {
                //1、创建文件对象
                File file = new File("D:\IO\hello.txt");
                //2、创建输入流对象
                fis = new FileInputStream(file);
                //用定义字节数组,作为装字节数据的容器
                byte[] buffer =new byte[5];
                int len;//记录每次读取的字节个数
                System.out.println(fis.read(buffer));
                while ((len=fis.read(buffer))!=-1){
                    //转成String型,否则输出ASCII码
                    String str=new String(buffer,0,len);
                    System.out.println(str);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                //释放资源
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
    
        }
    }
    运行结果:
    ABCDE
    FGH

      如果我们在读取的hello.txt文件中添加几个中文字,再次用同样的代码来运行看一下会发生什么情况(hello.txt内容 ABCDEFGH中国人):

      运行结果的截图:

    image

       可以发现运行的结果出现了乱码,这是因为每次读取五个字符,而一个utf-8的中文则占了3个字节,而第二次读取的时候【中】这个字的字节数并没有读完,而【国】字全部读完了,所以【中】和【人】字都出现了乱码而【国】没有出现乱码。这里画个图好理解一点。

    image

      为了避免可能出现的乱码,要么把 byte[] 数组容量增大,要么就使用字符输入输出流来处理(对于纯文本最好使用字符流)。

    2、字节输出流OutputStream

        OutputStream是所有字节输出流的父类,定义了所有字节输出流都具有的共同特征。其内部提供的方法如下:

    image

       上图中重载的三个write()方法都是用来写数据的。

    • void write(int b):把一个字节写入到文件中。
    • void write(byte[] b):把数组b 中的所有字节写入到文件中。
    • void write(byte[] b,int off,int len):把数组b 中的字节从 off 索引开始的 len 个字节写入到文件中。

    其中OutputStream的子类FileOutputStream是门用于读出文件中的数据,通过它将数据从程序输出到目标设备。

        FileOutputStream输出文件举例:

    package com.thr;
    
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    /**
     * @author Administrator
     * @date 2020-02-21
     * @desc 字节输出流FileOutputStream
     */
    public class FileOutputStreamTest {
    
        public static void main (String[] args)  {
            //定义字节输出流
            FileOutputStream fos =null;
            try {
    
                //1、创建文件对象
                File file = new File("D:\IO\hello.txt");
                //2、创建输出流对象
                fos = new FileOutputStream(file);
    
                fos.write(97);
                //后面的 
    表示回车换行
                fos.write("中国人!
    ".getBytes());
                //从索引2开始输出4个字节
                fos.write("ABCDEFGH".getBytes(),2,4);
    
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                //释放资源
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

           运行后结果是: a中国人!CDEF 。而如果我们多次运行测试代码会发现,每次运行完程序之后文件大小并没有改变,说明每次运行都创建了一次新的输出流对象,每次都清空目标文件中的数据。那么要如何才能保留目标文件中数据,还能继续追加新数据呢?其实很简单,如下两个FileOutputStream构造方法:

        public FileOutputStream(File file, boolean append)

        public FileOutputStream(String name, boolean append)

    这两个构造方法,第二个参数中都需要传入一个boolean类型的值,true表示追加数据,false表示不追加也就是清空原有数据。

    3、字节流拷贝文件

        在应用程序中,IO流通常都是成对出现的,即输入流和输出流一起使用。而文件的拷贝就需要通过输入流来读取文件中的数据,通过输出流将数据写入文件。

    package com.thr;
    
    import java.io.*;
    
    /**
     * @author Administrator
     * @date 2020-02-21
     * @desc 将文件从D盘拷贝到C盘
     */
    public class FileInputOutputStreamTest {
        public static void main(String[] args) {
    
            //定义输入流
            FileInputStream fis =null;
            //定义输出流
            FileOutputStream fos=null;
    
            //idea的try-catch快捷键Ctrl+Alt+T
            try {
                //创建文件对象
                File f1 = new File("D:\IO\1.jpg");
                File f2 = new File("C:\2.jpg");
                //创建输入输出流对象
                fis = new FileInputStream(f1);
                fos = new FileOutputStream(f2);
                //读取
                byte [] bytes = new byte[1024];
                int len;
                //读出
                while((len=fis.read(bytes))!=-1){
                    fos.write(bytes, 0, len);
                }
                System.out.println("拷贝成功...");
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                //释放
                try {
                    fis.close();
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
  • 相关阅读:
    php hook example
    sql 建立数据库,表格,索引,主键
    js 高级函数 之示例
    js 事件
    DOM 操作内容 innerText/innerHTML
    DOM 之 document 查找元素方法
    BOM 之 screen history
    Hadoop源码篇--Client源码
    Spark算子篇 --Spark算子之combineByKey详解
    Pandas库的使用--Series
  • 原文地址:https://www.cnblogs.com/tanghaorong/p/12341824.html
Copyright © 2011-2022 走看看