浅谈Java中的io流,小白都能看懂的io流入门篇

浅谈Java中的io流,小白都能看懂的io流入门篇

io流是JavaSE高级篇中的重要内容,不管是平时学习,还是面试,或是工作中,我们都会经常碰到io流,本文将带你从小白入门io流,掌握io流中的基础概念及重要内容。

File类详解

谈论io流之前,我们先来了解一下File类。

File类的理解

​ File,很好理解,英文翻译过来就是文件的意思。Java中的File类声明在java.io包下,由此也可以看出,File类和io流是密不可分的,互相联系的。其实,说白了,io流就是为File对象服务的。File类的一个对象,表示一个文件或一个文件目录(也就是文件夹)。

File类中涉及到关于文件或文件目录的创建、删除、重命名、修改时间、文件大小等方法,并未涉及到写入或读取文件内容的操作。如果需要读取或写入文件内容,必须使用IO流来完成。

下面讲一下File类的实例化,通常有下面几个构造器:

  • File(String filePath)
  • File(String parentPath,String childPath)
  • File(File parentFile,String childPath)
  • File(URI uri)

一般最常用的是第一个构造器,即传入一个参数,该参数为文件的路径。说到路径,这里又要引入绝对路径和相对路径了。

什么是绝对路径,什么是相对路径?

绝对路径:包含盘符在内的文件或文件目录的路径。举个栗子,在我电脑的D盘下的pictures文件夹下有个beauty文件夹,那么"D:\pictures\beauty"就是绝对路径,再比如,还在我这个电脑D盘下,还是pictures文件夹,还是该文件夹下的beauty文件夹下有个my future girlfriend.jpg的图片,

在这里插入图片描述

那么"D:\pictures\beauty\my future girlfriend.jpg"就是该图片文件的绝对路径。

那什么是相对路径呢?

相对路径:相较于某个路径下,指明的路径。

乍一看,有点抽象,没事,举个栗子你就明白了。

现在大家都是用IDEA开发吧,在IDEA中,如果大家开发使用JUnit中的单元测试方法测试,相对路径即为当前Module下。
如果大家使用main()测试,相对路径即为当前的Project下。

在这里插入图片描述

如上图,在该project下有个hello.txt文件,如果用相对路径的写法创建File对象(基于在main()方法中创建)就应该这样写

File file = new File("hello.txt");

所以说,相对路径是相对于某一路径下指明的路径,以该例子来看,就是相对于该project指明的路径。

再说一下一个写路径的小细节,路径分隔符

windows和DOS系统默认使用“\”来表示(当然也可以用"/"表示)

UNIX和URL使用“/”来表示

所以我们在写路径时可以有两种写法:

//第一种:用"/"表示
File file = new File("D:/pictures/beauty/my future girlfriend");
//第二种:用”\“表示,要用两个"\",其中第一个“\”表示转义
File file1 = new File("D:\\pictures\\beauty\\my future girlfriend")

File类的常用方法

在这里插入图片描述

好了,说完了File类,接下来进入今天的重头戏:io流

io流介绍

流的分类

根据不同的分类依据,io流可以分为一下3类

  • 根据操作的数据单位分为:字节流 字符流

  • 根据数据的流向分为:输入流 输出流

  • 根据流的角色分为:节点流 处理流

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

    流的体系结构

在这里插入图片描述

其中,4个抽象基类:InputStream、OutputStream、Reader、Writer,及蓝框中的类需要大家重点记忆及掌握。

重点说明的几个流结构

抽象基类节点流(文件流)缓冲流(处理流的一种)
InputStreamFileInputStream(read(byte[] buffer))BufferedInputStream
OutputStreamFileOutputStream(write(byte[] buffer,0,len))BufferedOutputStream
ReaderFileReader(read(char[] cbuf))BufferedReader
WriterFileWriter(write(char[] cbuf,0,len))BufferedWriter

输入输出的标准化过程

输入过程
  1. 创建File类的对象,指明读取的数据的来源(File类构造器参数为文件的路径),要求该文件一定要存在

  2. 创建相应的输入流对象,将File类的对象作为参数,传入流的构造器中

  3. 具体的读入数据的过程:

     创建相应的byte[] buffer 或 char[] cbuf
    

    ​ 注意:文本文件创建char[] cbuf,非文本文件创建byte[] buffer

  4. 关闭流资源

    说明:程序中出现的异常需要用try-catch-finally处理

输出过程
  1. 创建File类的对象,指明写出的数据的位置。(不要求此文件一定要存在)

  2. 创建相应的输出流,将File类的对象作为参数,传入流的构造器中

  3. 具体的写出数据的过程:

    ​ write(cbuf/buffer,0,len)

  4. 关闭流资源

    同样,程序中出现的异常需要用try-catch-finally处理

节点流

节点流也叫文件流,有FileInputStream、FileOutputStream、FileReader、FileWriter这几个类。

FileInputStream、FileOutputStream属于字节流,常用来处理图片、音频、视频等(.jpg,.mp3,.mp4,.avi,.doc,.ppt等为后缀的文件)非文本文件

FileReader、FileWriter属于字符流,常用来处理文本文件(.txt,.java,.c,.cpp等为后缀的文件)

FileReader/FileWriter的使用
FileReader的使用

案例:将该project下的hello.txt文件内容读入程序中,并输出到控制台

/*
    将该project下的hello.txt文件内容读入程序中,并输出到控制台
 */
public class Test {
    public static void main(String[] args) {

        FileReader fr = null;

        try {
            //创建文件对象
            //因为hello.txt文件就在这个project目录下,所以使用的相对路径
            File file = new File("hello.txt");

            //创建字符流对象,并将file对象作为参数传递
            fr = new FileReader(file);

            //创建一个字符数组存储读取的数据
            char[] cbuf = new char[5];
            //读取的字符长度
            int len;
            //read(char[] cbuf):返回每次读入cbuf数组中的字符的个数。如果达到文件末尾,返回-1
            while ((len = fr.read(cbuf)) != -1){
                //将char[] cbuf转换成字符串输出
                String s = new String(cbuf, 0, len);
                System.out.print(s);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭流资源,先判断流是否为空
            if (fr != null) {
                try {
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

注意点:

  • read(char[] cbuf)返回每次读入字符数组中的字符个数,若读到文件末尾返回-1

  • 读入的文件一定要存在,否则就会报FileNotFoundException

  • 对异常的处理,一定要用try-catch-finally,在finally语句中关闭流资源,以确保流资源一定会关闭,

    这样就不会导致如果前面的代码出现了异常,后面的关闭流资源不会执行的情况

    FileReader读入数据操作总结
    1. 实例化File类对象

    2. 实例化FileReader流对象

    3. 读取操作

      char[] cbuf = new char[5];
      int len;
      while((len = fr.read(cbuf)) != -1){
          //将char[] cbuf转换成字符串输出
          String s = new String(cbuf, 0, len);
          System.out.print(s);
      }
      
    4. 关闭流资源

    FileWriter的使用

    功能:从内存中写出数据到硬盘的文件里。

    说明:

    • 输出操作,对应的File可以不存在的。并不会报异常

    • File对应的硬盘中的文件如果不存在,在输出的过程中,会自动创建此文件。

      File对应的硬盘中的文件如果存在:
             如果流使用的构造器是:FileWriter(file,false) / FileWriter(file):对原文件的覆盖
             如果流使用的构造器是:FileWriter(file,true):不会对原文件覆盖,而是在原文件基础上追加内容
      

    案例:

@Test
public void testFileWriter() {
    FileWriter fw = null;
    try {
        //1.提供File类的对象,指明写出到的文件
        File file = new File("hello1.txt");

        //2.提供FileWriter的对象,用于数据的写出
        fw = new FileWriter(file,false);

        //3.写出的操作
        fw.write("I have a dream!\n");
        fw.write("you need to have a dream!");
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        //4.流资源的关闭
        if(fw != null){

            try {
                fw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

缓冲流

缓冲流是处理流的一种

缓冲流涉及到的类有:

  • BufferedInputStream(缓冲字节输入流)

  • BufferedOutputStream(缓冲字节输出流)

  • BufferedReader(缓冲字符输入流)

  • BufferedWriter(缓冲字符输出流)

已经有了字节流可以解决文本和非文本文件的数据读写问题,为什么还要引入缓冲流呢?

缓冲流相比于字节流有哪些优点?

缓冲流,顾名思义,可以起到一个缓冲的作用。它内部提供了一个缓冲区,默认大小为8kb,提高了流的读写速度。

在这里插入图片描述

所以,相比于节点流,我们会优先使用缓冲流读写文件,提高读写速度。

关于io流的笔试面试中会经常遇到诸如文件复制的问题,这类问题可以用节点流处理,也可以使用缓冲流处理

下面将使用字节流和缓冲流实现文本文件和非文本文件的复制

/*
    使用io流复制一个图片或者文本文件
    图片:非文本文件,使用字节流:FileInputStream/FileOutputStream or BufferedInputStream/BufferedOutputStream
    文本文件:使用字符流:FileReader/FileWriter or BufferedReader/BufferedWriter
 */
public class IoCopy {
    public static void main(String[] args) throws IOException {

        //创建文件对象(源文件和目标文件)
        File srcFile = new File("D:\\pictures\\02.jpg"); //源文件(路径)必须存在
        File destFile = new File("D:\\pictures\\02copy.jpg"); //目标文件(路径)可以不存在

//        copyTextWithBuffer(srcFile,destFile);
        copyImgWithBuffer(srcFile,destFile);

    }


    //使用字节流复制图片
    public static void copyImg(File srcFile, File destFile){

        //创建字节流对象
        FileInputStream inputStream = null;
        FileOutputStream outputStream = null;
        try {
            inputStream = new FileInputStream(srcFile);
            outputStream = new FileOutputStream(destFile);
            //创建字节数组存储读取到的数据
            byte[] data = new byte[5];
            int len; //字节数组的长度
            //read()每次返回读取的字节的长度,到达文件末尾返回-1
            while ((len = inputStream.read(data)) != -1) {
                outputStream.write(data, 0, len);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭资源
            if(outputStream != null){
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if(inputStream != null){
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }


        }

    }

    //使用字符流复制文本文件
    public static void copyText(File srcFile, File destFile) {


        FileReader reader = null;
        FileWriter writer = null;

        try {
            //造流
            reader = new FileReader(srcFile);
            writer = new FileWriter(destFile);

            //创建一个字符数组存储数据
            char[] data = new char[5];
            int len; //读取的字符长度
            //read()每次返回读取的字符的长度,到达文件末尾返回-1
            while ((len = reader.read(data)) != -1) {
                writer.write(data, 0, len);
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭字节流
            if(writer != null){
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if(reader != null){
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    //使用缓冲流复制文本文件
    /*
        使用缓冲流的好处:提高流的读写速度,因为内部有一个缓冲区,默认大小为8kb
     */

    public static void copyTextWithBuffer(File srcFile, File destFile) {

        FileReader reader = null;
        FileWriter writer = null;

        BufferedReader br = null;
        BufferedWriter bw = null;

        try {
            //创建字符流对象
            reader = new FileReader(srcFile);
            writer = new FileWriter(destFile);

            //创建缓冲流对象,把字符流对象作为参数传递
            br = new BufferedReader(reader);
            bw = new BufferedWriter(writer);

            //复制的细节
            //创建一个char[]类型数组,用于存储读取的字符数据
            char[] data = new char[1024];
            int len; //读取到的字符长度
            //read()返回读取的字符长度,当返回-1时表示读取到了文件末尾
            while ((len = br.read(data)) != -1) {
                bw.write(data, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {

            //关闭流,先关闭外层流(缓冲流),关闭外层流,内层流(节点流)会自动关闭,可以省略
            if (bw != null) {
                try {
                    bw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }


        }

    }


    //使用缓冲流复制图片等非文本文件
    public static void copyImgWithBuffer(File srcFile,File destFile){

        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;

        try {
            //创建缓冲流及字节流对象,并传递参数
            bis = new BufferedInputStream(new FileInputStream(srcFile));
             bos = new BufferedOutputStream(new FileOutputStream(destFile));

            //复制
            byte[] data = new byte[1024];
            int len;
            while ((len = bis.read(data)) != -1){
                bos.write(data,0,len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭流
            try{
                if(bos != null){
                    bos.close();
                }
            }catch (Exception e){
                e.printStackTrace();
            }

            try{
                if(bis != null){
                    bis.close();
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
}


以上就是JavaSE中io流入门的基础内容,也是io流中的核心内容。因编者本人水平有限,难免存在疏漏与不足,望广大网友指出,感谢!

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值