详解 字节输出流 与 字节输入流

(请观看本人博文——《详解 字节流 与 字符流》

对于字节流而言,我们主要应用它的四个子类 —— FileOutputStream类 与 FileInputStream类 和 BufferedOutputStream类与BufferedInputStream类,它们都是字节输出/输入流,只不过存在效率问题
那么,现在,本人就来讲解下这四个类的 基本知识点:

首先,在讲解所有内容之前,本人要着重强调一个问题:

流用完之后,必须释放资源!!!(即:close()掉)


FileOutputStream类

(字节型输出流)

概念

内存文件 输出的流

首先,本人来展示下它的 构造方法

  • FileOutputStream(File file)
  • FileOutputStream(String name)

(若是我们所传的参数所表示的文件不存在,则会自动创建一个相应的文件

为了验证上面的讲解,本人来展示下:
首先,本人来给出一段代码:

package edu.youzg.about_io.about_file.core;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;

public class Test {

    public static void main(String[] args) throws FileNotFoundException {
        File file = new File("test.txt");
        FileOutputStream out = new FileOutputStream(file);
        out.close();
    }

}

现在,本人先来展示运行前的目录:
在这里插入图片描述
现在,本人再来展示下运行后的目录:
在这里插入图片描述
那么,本人在上面的讲解是正确的。

现在,本人来展示下 FileOutputStream类 的常用API

  • public void write(int b, boolean append):
    一个字节
    (超过一个字节,则只录入最后一个字节
  • public void write(byte[] b, boolean append):
    一个字节数组
  • public void write(byte[] b, int off, int len, boolean append):
    一个字节数组的一部分

在这里本人还要强调一点:

  • 若是我们在参数中不写append参数,则默认append为false,则:
    将原文件中的所有内容就会被删除,然后再将我们程序中设定的内容写进去
  • 若我们的append参数设置为true,则:
    在原内容的最后一个字节处后增添新内容

那么,现在本人来展示下这三个方法的使用:

package edu.youzg.about_io.about_file.core;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

public class Test {

    public static void main(String[] args) throws IOException {
        File file = new File("test.txt");
        FileOutputStream out = new FileOutputStream(file);

        out.write(99);
        out.write(new byte[] {'b', 101, 102});
        out.write(new byte[] {98, 104, 103}, 1, 1);

		//流用完之后,必须释放资源
        out.close(); //关闭流
    }

}

那么,现在本人来展示下运行结果:
在这里插入图片描述
可以看到,文件中按照我们的需要录入了信息。

那么,本人再在这里啰嗦一句:

汉字在UTF-8中占3个字节
汉字在GBK中占2个字节

现在,本人还要强调一点:
若是我们想要在输入的内容中做到换行,就要用到换行符

换行符:

  • windows ---------- \r\n
  • Linux -------------- \n
  • Mac ---------------- \r

那么,本人再来展示下上面两个知识点的使用:

package edu.youzg.about_io.about_file.core;

import java.io.FileOutputStream;
import java.io.IOException;

public class Test {

    public static void main(String[] args) throws IOException {
        FileOutputStream out = new FileOutputStream("test.txt");
        out.write("芷若幽兰,寂静无言".getBytes());
        out.write("\r\n".getBytes());//写入一个回车换行符
        out.write("白芷杜若,相濡以沫".getBytes());

        byte[] bytes = "白".getBytes();
        System.out.println("一个汉字在UTF-8下长度为" + bytes.length + "个字节");

        //流用完之后,必须释放资源
        out.close(); //关闭流
    }

}

现在,本人来展示下运行结果:
在这里插入图片描述
上图可以证明:汉字在UTF-8编码下占3个字节!

现在,本人来展示下运行后的test.txt的内容:
在这里插入图片描述
可以看到,我们通过代码所输入的内容换行了!

那么

那么,现在,本人来讲解下 FileInputStream类

FileInputStream类:

(字节输入流)

概念

文件内存 输入的流

首先,本人来展示下这个类的 构造方法

  • FileInputStream(File file)
    通过打开一个到实际文件的连接来创建一个 FileInputStream,
    该文件通过文件系统中的 File 对象 file 指定。
  • FileInputStream(FileDescriptor fdObj)
    通过使用文件描述符 创建一个 FileInputStream,
    该文件描述符表示到文件系统中某个实际文件的现有连接。
  • FileInputStream(String name)
    通过打开一个到实际文件的连接来创建一个 FileInputStream,
    该文件通过文件系统中的路径名 name 指定。

关于这个类的的构造方法,本人再强调一点:
若是文件不存在,就会报异常

现在,本人来展示下这个类的常用API

  • int read()
    从此输入流中读取一个数据字节
  • int read(byte[] b)
    从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中
  • int read(byte[] b, int off, int len)
    从此输入流中将最多 len 个字节的数据读入一个 byte 数组中

(注意:每次读取后会使得流的指向变为下一个字节

现在,本人来展示下read()方法的使用:

package edu.youzg.about_io.about_file.core;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class Test {

    public static void main(String[] args) throws IOException {
        FileInputStream in = new FileInputStream("test.txt");

        int len = in.read();//一次读取一个字节
        System.out.println(len);

        byte[] bytes1 = new byte[1024];
        byte[] bytes2 = new byte[1024];
        //读取字节数组的一部分
        //把读取到的字节的一部分,装入到缓冲区中
        int len1 = in.read(bytes1, 0, 3);    //从指定位置开始,读取指定长度
        //返回值是 读取出来的字节数组的长度
        System.out.println(len1);
        int len2 = in.read(bytes2, 0, 3);    //从指定位置开始,读取指定长度
        //返回值是 读取出来的字节数组的长度
        System.out.println(len2);

        //我们将读取到的字节数组转化为字符串
        String s = new String(bytes1, 0, 3);
        System.out.println(s);
        s = new String(bytes2, 0, 3);
        System.out.println(s);

        in.close();
    }

}

那么,本人来展示下运行结果:
在这里插入图片描述

相信同学们已经对这两个类的使用了解了
那么,现在,本人现在来通过一个例子来巩固下同学们对于这两个知识点的理解:
本人现在来展示下如何用上述两个类来“复制Mp3文件”:

首先,本人先来展示一个很简单的方法——通过每次读取一个字节来完成复制:

package edu.youzg.about_io.about_file.core;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class Test {

    public static void main(String[] args) {
        FileInputStream in = null;
        FileOutputStream out = null;
        try {
            in = new FileInputStream("test.mp3");
            out = new FileOutputStream("copyView1.mp3");
            int len=0;
            long start = System.currentTimeMillis();
            while ((len=in.read())!=-1){
                out.write(len);
                out.flush();	//清空缓存区内容,并将其输出
            }
            long end = System.currentTimeMillis();
            System.out.println((end-start)+"毫秒");	//记录最终用时
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {	//流在使用完之后,一定要释放资源
            try {
                in.close();
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

那么,本人再来展示下生成的文件和源文件:
在这里插入图片描述
现在,我们来看一下运行结果:
在这里插入图片描述
可以看到,用时很长,
那么,为了缩短用时,本人再来给出一套方案 —— 每次读取一个字节数组,来充当缓冲区,以便于我们完成复制:

package edu.youzg.about_io.about_file.core;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class Test {

        public static void main(String[] args) {
            FileInputStream in = null;
            FileOutputStream out = null;
            try {
                in = new FileInputStream("test.mp3");
                out = new FileOutputStream("copyView2.mp3");
                //定义一个字节数组,充当缓冲区
                byte[] bytes = new byte[1024 * 1024];
                int len = 0;//记录每次读取到的有效字节个数
                long start = System.currentTimeMillis();
                while ((len = in.read(bytes)) != -1) {
                    out.write(bytes, 0, len);
                    out.flush();	//清空缓存区内容,并将其输出
                }
                long end = System.currentTimeMillis();
                System.out.println((end - start) + "毫秒");
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {	//流在使用完之后,一定要释放资源
                try {
                    in.close();
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

    }

}

本人来展示下生成的文件和源文件:
在这里插入图片描述
那么,我们再来看一下用时:
在这里插入图片描述
可以看到,缩短和了用时!


其实,以本人上面的构造缓冲区来缩短运行时间的思想,Java有一个专门封装好的类,用于处理对大文件的读和写的操作 ——
BufferedInputStream 和 BufferedOutputStream:

BufferedOutputStream

(高效字节输出流)

现在,本人来讲解下这个类的构造方法

BufferedOutputStream(OutputStream out)
BufferedOutputStream(OutputStream out, int size)
(注:参数size决定了缓冲区的大小,
如果不写的话,则默认为8192字节)

至于常用API,就是write(),参数和FileOutputStream的write()方法的参数一样。


BufferedInputStream

(高效字节输入流)

现在,本人来讲解下这个类的构造方法

BufferedInputStream(InputStream out)
BufferedInputStream(InputStream out, int size)
(注:参数size决定了缓冲区的大小,
如果不写的话,则默认为8192字节)

至于常用API,就是read(),参数和FileInputStream的read()方法的参数一样。


那么,现在,本人就利用这两个类,来实现下文件的复制

package edu.youzg.about_io.about_file.core;

import java.io.*;

public class Test {

    public static void main(String[] args) {
        //高效的字节输入输出流
        BufferedInputStream bfr = null;
        BufferedOutputStream bfw = null;
        try {
            bfr = new BufferedInputStream(new FileInputStream("test.mp3"));
            bfw = new BufferedOutputStream(new FileOutputStream("copyView3.mp3"));
            int len=0;
            byte[] bytes = new byte[1024 * 8];
            long start = System.currentTimeMillis();
            while ((len=bfr.read(bytes))!=-1){
                bfw.write(bytes,0,len);
            }
            long end = System.currentTimeMillis();
            System.out.println((end - start) + "毫秒");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                bfr.close();
                bfw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}

现在,本人来展示下生成的文件和源文件:
在这里插入图片描述
那么,本人在来展示下运行时间:
在这里插入图片描述
第一次文件复制所用的时间是87670ms
第二次文件复制所用的时间是28ms
本次文件复制所用的时间是49ms

可以看到,对于大文件而言,我们利用缓冲区的思想来读和写比一个字节一个字节地读写的效率更高
而本次和第二次的远离大致相同,至于为什么比第二次慢,是因为第二次所设置的缓冲区比默认值大,我们可以自己去设置缓冲区大小。

那么,有关 字节输出流 与 字节输入流的基本知识点在这里就讲解完了。
(本人《详解 字节流 与 字符流》博文链接:https://blog.csdn.net/weixin_45238600/article/details/104170259
(本人“I/O流”总集篇博文链接:https://blog.csdn.net/weixin_45238600/article/details/104153031

发布了118 篇原创文章 · 获赞 82 · 访问量 5205

猜你喜欢

转载自blog.csdn.net/weixin_45238600/article/details/104175729
今日推荐