Java IO流 ——转换流&管道流&打印流&缓冲流(文件拷贝案例,打印流——装饰者模式)

转换流(了解)

  • 整体继承关系

image

package com.io.demo;

import java.io.*;

public class Demo5 {
    public static void main(String[] args) {
        File file = new File("D:\\Javaproject\\test\\b.txt");//创建文件对象
        if (!file.exists()) {// 判断文件是否存在
            file.getParentFile().mkdirs();// 如果不存在通过父节点文件路径创建路径文件夹
            try {
                file.createNewFile();// 创建文件
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        OutputStream os = null;
        Writer writer = null;
        try {
            os = new FileOutputStream(file);  // 字节流
            writer = new OutputStreamWriter(os);  // 字节流转化成字符流 向上转型
            writer.write("你好世界");  // 可以直接进行字符串的输出,方便处理中文
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                writer.close();
                os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
  • 这种转换流在一些系统类库的操作之中比较常见,有些情况下系统只会给用户字节流,但是为了处理方便需要进行字符流的转化。

  • 类的继承关系

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rZGxs4j0-1596290340897)(https://s1.ax1x.com/2020/08/01/a3WXRS.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pZa0dK5b-1596290600428)(https://s1.ax1x.com/2020/08/01/a3fKd1.png)]

  • 文件拷贝案例

    package com.io.demo;
    
    import java.io.*;
    import java.util.Date;
    
    public class Demo6 {
        public static void main(String[] args) {
    
            File srcFile = new File("D:\\Javaproject\\test\\仓库管理环境监测系统.mp4");
            File desFile = new File("D:\\Javaproject\\test\\copy仓库管理环境监测系统.mp4");
            try {
                int time = copyFile(srcFile, desFile);
                System.out.println("执行时间:"+time);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        public static int copyFile (File srcFile, File desFile) throws IOException {
    
            long start = new Date().getTime();
            if (!srcFile.exists()) {//判断源文件是否存在
                throw new FileNotFoundException("未找到源文件"); // 若源文件不存在抛出异常
            } else {
                if (!desFile.exists()) {// 判断目标文件是否存在
                    desFile.getParentFile().mkdirs(); // 创建父路径
                    try {
                        desFile.createNewFile(); //创建文件
                    } catch (IOException e) {
                        throw new IOException();
                    }
                }
    
                /*IO操作
                  0.因为文件可能是纯字符文件也可能是图片、视频等二进制文件所以这里采用字节流
                * 1. 从源文件读取字节到字节缓冲区
                * 2. 从缓冲区将字节写入目标文件
                * 3.关闭流
                * */
                byte buf[] = new byte[2048];  // 创建一个字节数组作为缓冲区
                InputStream ins = new FileInputStream(srcFile); // 创建字节输入流
                OutputStream os = new FileOutputStream(desFile); // 创建字节输出流
                int len; // 记录读取到的字节数
                while ((len = ins.read(buf)) != -1) {  // 从源文件中读取字节
                    os.write(buf, 0, len); // 将读取到的字节写入到目标文件
                }
                ins.close(); // 关闭字节输入流
                os.close(); // 关闭字节输出流
            }
            long end = new Date().getTime();
            return (int)(end - start);
        }
    }
    
  • 我们之前的操作数据来源都是文件,所以我们称之为文件流

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9wsJ8rT9-1596290340904)(https://s1.ax1x.com/2020/08/01/aGULgx.png)]

  • 实际开发过程中,更多的数据来源可能不是来源于文件,这时候就需要内存流。

  • 内存流继承结构

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DfRJZENZ-1596290510272)(https://s1.ax1x.com/2020/08/01/aGUU3t.png)]

  • 内存流

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eyoJ8TcG-1596290458888)(https://s1.ax1x.com/2020/08/01/a8Wly4.png)]

  • Class ByteArrayInputStream

构造方法
ByteArrayInputStream(byte[] buf) 创建一个 ByteArrayInputStream ,使其使用 buf作为其缓冲区数组。
ByteArrayInputStream(byte[] buf, int offset, int length) 创建 ByteArrayInputStream使用 buf作为其缓冲器阵列。
  • 方法解析
方法解析
int read()从该输入流读取下一个数据字节。
int read(byte[] b, int off, int len)将 len字节的数据读入此输入流中的字节数组。
  • Class ByteArrayOutputStream

构造方法
ByteArrayOutputStream()创建一个新的字节数组输出流。
ByteArrayOutputStream(int size)创建一个新的字节数组输出流,具有指定大小的缓冲区容量(以字节为单位)。
  • 方法解析
方法解析
void write(byte[] b, int off, int len)从指定的字节数组写入 len字节,从偏移量为 off开始,输出到这个字节数组输出流。
void write(int b)将指定的字节写入此字节数组输出流。
void writeTo(OutputStream out)将此字节数组输出流的完整内容写入指定的输出流参数,就像使用 out.write(buf, 0, count)调用输出流的写入方法 out.write(buf, 0, count) 。

管道流(了解)

  • 概述
    • 管道流是用来在多个线程之间进行信息传递的Java流。
    • 管道流分为字节流管道流和字符管道流。
    • 字节管道流:PipedOutputStream 和 PipedInputStream。
    • 字符管道流:PipedWriter 和 PipedReader。
    • PipedOutputStream、PipedWriter 是写入者/生产者/发送者;
    • PipedInputStream、PipedReader 是读取者/消费者/接收者。

image

  • public class PipedInputStream
    extends InputStream
    
  • public class PipedOutputStream
    extends OutputStream
    
package com.io.demo;


import java.io.*;

public class Demo7 {
    public static void main(String[] args) {
        SendThread send = new SendThread();
        Receive receive = new Receive();
        try {
            send.getOs().connect(receive.getIns());  // 管道对接
        } catch (IOException e) {
            e.printStackTrace();
        }
        new Thread(send).start();
        new Thread(receive).start();
    }
}

class SendThread implements Runnable{

    private PipedOutputStream os = new PipedOutputStream();
    @Override
    public void run() {
        try {
            os.write("你好Receive".getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public PipedOutputStream getOs() {
        return os;
    }
}

class Receive implements Runnable{

    private PipedInputStream ins = new PipedInputStream();
    private byte[] buf = new byte[1024];

    public PipedInputStream getIns() {
        return ins;
    }

    @Override
    public void run() {
        try {
            ins.read(buf);
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                ins.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            System.out.println(new String(buf));
        }
    }
}

打印流(掌握)

  • OutputStream、和Write 功能设计的不足,只能实现字符串或字节数组的输出,但是从实际的开发来讲,输出操作可能会有各种数据类型。

    PrintStream为另一个输出流添加了功能,即能够方便地打印各种数据值的表示。

    还提供了另外两个功能。

    与其他输出流不同, PrintStream从不抛出IOException ;

    相反,异常情况只是设置一个可以通过checkError方法测试的内部标志。

    可以选择一个PrintStream ,以便自动刷新;

    这意味着flush字节数组写入方法后自动调用,所述一个println方法被调用时,或者一个新行字符或字节( '\n' )被写入。

    由印刷的所有字符PrintStream被转换成使用平台的默认字符编码字节。 在需要编写字符而不是字节的情况下,应使用PrintWriter类。

  • 先观察我们自己通过再封装的形式定义的类打印流的打印工具类

package com.io.demo;

import java.io.*;

public class Demo8 {
    public static void main(String[] args) throws IOException {
        File file = new File("D:\\Javaproject\\test\\b.txt");
        PrintUtil printUtil = new PrintUtil(new FileOutputStream(file));
        printUtil.println("张三");
        printUtil.print("性别:男 年龄:");
        printUtil.print(18);
        printUtil.close();
    }
}

class PrintUtil implements Closeable {
    private OutputStream os;

    public PrintUtil(OutputStream os) {
       this.os = os;
    }

    public void print(int i) {
        try {
            this.os.write((i + "").getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void println(int i) {
        try {
            this.os.write((i + "").getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
        this.println();
    }


    public void print(String str) {
        try {
            this.os.write(str.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void println(String str) {
        try {
            this.os.write(str.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
        this.println();
    }

    private void println() {
        try {
            this.os.write("\r\n".getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void close() throws IOException {
        this.os.close();
    }
}

  • 上边是我们自己定义的打印工具类,其本质上用的是字节流,只是形式上的改变,使其功能升级,这样的设计思想,我们称之为 装饰者模式,打印流就是采取了这种模式进行开发的。

  • PrintStreamPrintWriter 继承关系

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9xnXy2KD-1596290363541)(https://s1.ax1x.com/2020/08/01/aG18KJ.png)]

package com.io.demo;

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

public class Demo9 {
        public static void main(String[] args) throws FileNotFoundException {
            File file = new File("D:\\Javaproject\\test\\b.txt");
            PrintWriter pw = new PrintWriter(new FileOutputStream(file));
            pw.println("张三");
            pw.print("性别:男 年龄:");
            pw.print(18);
            pw.close();
        }
}
  • 此外PrintWriter类还提供了大量的方法 —> API直通车

  • 打印流格式化输出:

package com.io.demo;

import java.io.*;

public class Demo10 {
    public static void main(String[] args) throws FileNotFoundException {
        File file = new File("D:\\Javaproject\\test\\b.txt");
        PrintWriter pw = new PrintWriter(new FileOutputStream(file));
        String name = "张三";
        char gender = '男';
        int age = 18;
        pw.printf("姓名:%s 性别:%c 年龄:%d ", name, gender, age);
        pw.close();
    }
}

缓冲字节流

  • 缓冲字节流的实现原理其实就是在字节流的基础上增加了一个byte数组作为缓冲区,本质上就是字节流。

  • public class BufferedOutputStream extends FilterOutputStream

    该类实现缓冲输出流。 通过设置这样的输出流,应用程序可以向底层输出流写入字节,而不必为写入的每个字节导致底层系统的调用。

package com.io.demo;

import java.io.*;

public class Demo11 {
    public static void main(String[] args) throws IOException {
        File file = new File("D:\\Javaproject\\test\\b.txt");
        BufferedOutputStream bfo = new BufferedOutputStream(new FileOutputStream(file));
        /*
            构造方法:
            public BufferedOutputStream(OutputStream out) {
            this(out, 8192);
            }
             public BufferedOutputStream(OutputStream out, int size) {
            super(out);
            if (size <= 0) {
                throw new IllegalArgumentException("Buffer size <= 0");
            }
            buf = new byte[size];
            }
            size  ---> 字节缓冲区的大小,本质上就是一个字节流 套了一个buf缓冲字节数组
        *
        * */
        bfo.write("buffered 脱裤子放屁".getBytes());
        bfo.close();
    }
}

总结

  • 要学好IO流最重要的就是搞清楚字节流和字符流以及其子类之间的各种继承关系。
  • 巧妙运用字节缓冲区和装饰者模式可以比较好的提升IO流的性能。
  • 流不仅是限于文件之间的数据操作,对象还可以是内存。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Pointer-faker

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值