前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >18. 基础IO(2)——IO流

18. 基础IO(2)——IO流

作者头像
小雨的分享社区
发布2022-10-26 15:46:39
3810
发布2022-10-26 15:46:39
举报
文章被收录于专栏:小雨的CSDN小雨的CSDN

1. 字节流,字符流基本概念

File类不支持文件内容处理,如果要处理文件内容,必须要通过流的操作模式来完成

在java.io包中,流分为两种:字节流与字符流

字节流:读写数据以字节为基本单位(处理二进制文件/数据的时候使用) 字符流:独写数据以字符为基本单位(处理文本文档/数据的时候使用)

2. 字节流

1)InputStream:(输入)把输入设备读取到内存中 2)OutputStream:(输出)把内存中的数据写入到输出设备中

a)FileInputStream和FileOutputStream

FileInputStream 从文件系统中的某个文件中获得输入字节。 FileInputStream 用于读取诸如图像数据之类的原始字节流。

示例:复制图片 1)初阶:

代码语言:javascript
复制
package dqy0305;

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

public class IODemo2 {
    //实现文件的复制
    public static void main(String[] args) throws IOException {
        copyFile("D:/file_dir/1010.png","D:/file_dir/10102.png");
    }

    private static void copyFile(String srcPath, String destPath) throws IOException {
        //1.先打开文件(先创建InputStream和OutputStreaam对象的过程)
        FileInputStream fileInputStream = new FileInputStream(srcPath);
        FileOutputStream fileOutputStream = new FileOutputStream(destPath);
        //2.需要读取srcPath文件对应的内容
        byte[] buffer = new byte[1024];
        int len = -1;
        //如果已经读完了就返回-1.如果返回一个正数,就相当于一共有这个整数的长度
        while((len = fileInputStream.read(buffer)) != -1){
            //读取成功
            //3.把读取到的内容写入desrPath对应的文件中
            fileOutputStream.write(buffer,0,len);
        }
        //4.close关闭文件,如果没有关闭就会造成文件资源泄露
        fileInputStream.close();
        fileOutputStream.close();
    }
}

这时对应的文件里就已经复制好了一个图片

在这里插入图片描述
在这里插入图片描述

以上方法有可能正在执行过程中触发了异常,那么还是无法执行close(),并且在实例化fileInputStream和fileOutputStream的时候,如果指定位置的文件不存在,就会导致实例化失败,也就是说还是null,这时在调用close方法的时候就会触发空指针异常,也就有了以下的改进版本:

2)改进版

代码语言:javascript
复制
  public static void main(String[] args) throws IOException {
        copyFile2("D:/file_dir/1010.png","D:/file_dir/10102.png");
    }

private static void copyFile2(String srcPath, String destPath){
        FileInputStream fileInputStream = null;
        FileOutputStream fileOutputStream = null;

        try {
            //1.先打开文件(先创建InputStream和OutputStreaam对象的过程)
            fileInputStream = new FileInputStream(srcPath);
            //但是如果路径对应的文件不存在,此时构造方法也会抛出异常,说明构造尚未成功,还是null,
            // 那么接下来调用close方法就会触发空指针异常
            fileOutputStream = new FileOutputStream(destPath);
            //2.需要读取srcPath文件对应的内容
            byte[] buffer = new byte[1024];
            int len = -1;
            //如果已经读完了就返回-1.如果返回一个正数,就相当于一共有这个整数的长度
            while((len = fileInputStream.read(buffer)) != -1){
                //读取成功
                //3.把读取到的内容写入desrPath对应的文件中
                fileOutputStream.write(buffer,0,len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                //4.close关闭文件,如果没有关闭就会造成文件资源泄露
                if (fileInputStream != null) {
                    fileInputStream.close();
                }
                if (fileOutputStream != null) {
                    fileOutputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

但是以上代码在异常处理方面过于冗杂,为了提高代码的可读性,就有了以下版本: 3)常用版

代码语言:javascript
复制
  public static void main(String[] args) throws IOException {
        copyFile3();
    }

  private static void copyFile3(){
        //当代码写成这个样子的时候,就不需要显示调用close
        //try语句会在代码执行完毕后,自动调用close方法(前提是这个类必须实现closeable接口)
        try(FileInputStream fileInputStream = new FileInputStream("D:/file_dir/1010.png");
            FileOutputStream fileOutputStream = new FileOutputStream("D:/file_dir/10102.png")){
            byte[] buffer = new byte[1024];
            int len = -1;
            while ((len = fileInputStream.read(buffer)) != -1){
                fileOutputStream .write(buffer,0,len);
            }
        }catch (IOException e){
            e.printStackTrace();
        }

    }
b)字节缓冲流 BufferedInputStream 和 BufferedOutputStream(内置了缓冲区)

问题一:为什么需要有缓冲区?

答:当我们用read()读取文件时,每读一个字节,访问一次磁盘,效率很低 。文件过大时,操作起来也不是很方便。因此我们需要用到buffer缓存流,当创建buffer对象时,会创建一个缓冲区数组。当我们读一个文件时,先从磁盘中读到缓冲区,然后直接从缓冲区输出即可,效率会更高

实例:复制图片 1)初版

代码语言:javascript
复制
public class IODemo3 {
    public static void main(String[] args) throws IOException {
          copyFile();
    }

    private static void copyFile() throws IOException {
        //需要创建的实例 BufferedInputStream 和 BufferedOutputStream,就先要创建FileInputStream和FileOutputStream
        FileInputStream fileInputStream = new FileInputStream("D:/file_dir/1010.png");
        FileOutputStream fileOutputStream = new FileOutputStream("D:/file_dir/10102.png");
        BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
        byte[] buffer = new byte[1024];
        int length = -1;
        while ((length = bufferedInputStream.read(buffer)) != -1){
            bufferedOutputStream.write(buffer,0,length);
        }
        //有四个流对象,只需要关闭这两个,然后就会自动关闭包含的FileInputStream和FileOutputStream
        bufferedInputStream.close();
        bufferedOutputStream.close();
    }
}

2)改进版

代码语言:javascript
复制
 private static void copyFile2() {
        try( BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream("D:/file_dir/1010.png"));
             BufferedOutputStream bufferedOutputStream = new BufferedOutputStream( new FileOutputStream("D:/file_dir/10102.png"))) {

            byte[] buffer = new byte[1024];
            int length = -1;
            while ((length = bufferedInputStream.read(buffer)) != -1){
                bufferedOutputStream.write(buffer,0,length);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
c)带缓冲区和不带缓冲区的对比
代码语言:javascript
复制
    private static void testNoBuffer() {
        long beg = System.currentTimeMillis();
       try ( FileInputStream fileInputStream = new FileInputStream("D:/file_dir/1010.png")){
           int ch = -1;
           while ((ch = fileInputStream.read()) != -1){

           }
       } catch (IOException e) {
           e.printStackTrace();
       }
       long end = System.currentTimeMillis();
        System.out.println("no buffer:"+(end-beg)+"ms");
    }

    private static void testBuffer() {
        long beg = System.currentTimeMillis();
        try (BufferedInputStream bufferedInputStream= new BufferedInputStream(new FileInputStream("D:/file_dir/1010.png"))){
            int ch = -1;
            while ((ch = bufferedInputStream.read()) != -1){

            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        long end = System.currentTimeMillis();
        System.out.println("buffer:"+(end-beg)+"ms");

    }

执行主函数,就会发现,读取一个15MB的文件,不带缓冲区大概花了6s左右,但是带缓冲区大概只花了50ms

3. 字符流

1)Reader:(输入)把输入设备读取到内存中 2)Writer:(输出)把内存中的数据写入到输出设备中

字符流与字节流用法基本一致,一个典型的区别是: 字节流的读写操作以byte为单位,缓冲区就是byte[] 字符流的读写操作以char为单位,缓冲区就是char[]

示例: 1)不带缓冲区

代码语言:javascript
复制
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

//字符流:可以来处理文本文件
public class IODemo5 {
    public static void main(String[] args) {
        copyFile();
    }
    
    private static void copyFile(){
        try(FileReader fileReader = new FileReader("d:/test.txt");
            FileWriter fileWriter = new FileWriter("d:/test2.txt")){
            char[] buffer = new char[1024];
            int len = -1;
            while ((len = fileReader.read(buffer)) != -1){
                fileWriter.write(buffer,0,len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2)带缓冲区

代码语言:javascript
复制
 //带缓冲区
    private static void copyFile2(){
        try(BufferedReader bufferedReader = new BufferedReader(new FileReader("d:/test.txt"));
        BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("d:/test2.txt"))){
            char[] buffer = new char[1024];
            int len = -1;
            while ((len = bufferedReader.read(buffer)) != -1){
                bufferedWriter.write(buffer,0,len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

3)字符流中有特殊的用法:按行读取

代码语言:javascript
复制
   private static void copyFile3(){
        try(BufferedReader bufferedReader = new BufferedReader(new FileReader("d:/test.txt"));
            BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("d:/test2.txt"))) {
                String line = "";//读一行,读到换行符为止
                while ((line = bufferedReader.readLine()) != null){
                    bufferedWriter.write(line+ "\n");
                }
            } catch (IOException e) {
            e.printStackTrace();
        }
    }
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-03-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 字节流,字符流基本概念
  • 2. 字节流
    • a)FileInputStream和FileOutputStream
      • b)字节缓冲流 BufferedInputStream 和 BufferedOutputStream(内置了缓冲区)
        • c)带缓冲区和不带缓冲区的对比
        • 3. 字符流
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档