• Java学习【IO流:深入理解与应用(上)】


    在这里插入图片描述
    🚀所属专栏:Java学习⭐⭐
    🚀欢迎互三👉: 2的n次方_⭐⭐

    🍃1.IO流体系结构

    Java编程中,IO(Input/Output)流是一个非常重要的概念,它允许我们与各种数据源(如文件、网络、内存等)进行交互。Java的IO库提供了丰富的类和方法,用于读取和写入数据。

    IO流按照操作文件类型又可以分为
    字节流:可以操作所有类型文件
    字符流:只能操作纯文本文件
    在这里插入图片描述
    由于上面的四个都是抽象类,在实现的时候要创建子类的对象,这里以字节流为例,下面是其两个子类
    在这里插入图片描述

    🍃2.FileOutputStream

    FileOutputStream:操作本地文件的字节输出流,可以把程序中的数据写入到本地文件中。

    1.参数是字符串表示的路径或者File对象都可以
    2.如果文件不存在就会创建一个新的文件,但是要保证父级路径是存在的
    3.如果文件存在,那么会清空文件中的数据,然后再写入
    写入文件时,传入参数是整数,会转换为ASCII码对应的字符
    如果想要写入整型,就分开写对应的ASCII码

    🍁2.1FileOutputStream写数据的三种方式

    在这里插入图片描述

    创建对象之后是通过调用write()方法进行写入

    FileOutputStream fos = new FileOutputStream("E:\\java\\a.txt");
            // 写入一个数据
            fos.write(97);
    

    这里会出现异常,将异常进行抛出处理
    在这里插入图片描述
    write()也提供了其他的重载方法
    在这里插入图片描述

    可以传入一个byte类型的数组,写入多个字节,还可以指定写入的起始索引,再指出写入几个字节

            byte[] bytes = {97, 98, 99, 100};
            fos.write(bytes);
            //从1索引开始写入两个字符
            fos.write(bytes, 1, 2);
    

    每次执行操作结束之后都要调用close()方法进行资源释放,否则文件就会一直被占用
    在这里插入图片描述

    public class ByteStreamDemo1 {
        public static void main(String[] args) throws IOException {
            FileOutputStream fos = new FileOutputStream("E:\\java\\a.txt");
            // 写入一个数据
            fos.write(97);
    		//写入多个数据
            byte[] bytes = {97, 98, 99, 100};
            fos.write(bytes);
            //从1索引开始写入两个字符
            fos.write(bytes, 1, 2);
            //释放资源,解除资源占用
            fos.close();
        }
    }
    

    🍁2.2换行和续写

    除了以上三种写入方式外,还可以通过字符串的方式进行写入
    此外,如果需要写入换行,在windows操作系统中,是用 “\r\n” 表示换行

    public class ByteStreamDemo1 {
        public static void main(String[] args) throws IOException {
    
            FileOutputStream fos = new FileOutputStream("E:\\java\\a.txt");
            //写入字符串
            String str = "hello";
            byte[] bytes1 = str.getBytes();
            fos.write(bytes1);
            //写入换行
            String s = "\r\n";
            fos.write(s.getBytes());
            fos.write(97);
            //释放资源,解除资源占用
            fos.close();
        }
    }
    

    打开记事本查看a.txt的内容
    在这里插入图片描述
    续写就是不清空原来文件的内容,接着往下写
    FileOutputStream()的构造方法还有一个boolean类型的参数,表示续写开关,默认是false,如果创建对象时给出true,那么就表示续写,此时就不会清空原来文件的内容
    在这里插入图片描述

    public class ByteStreamDemo1 {
        public static void main(String[] args) throws IOException {
            //续写,之前内容不会清空
            FileOutputStream fos1 = new FileOutputStream("E:\\java\\a.txt", true);//打开续写
            fos1.write("666".getBytes());
            //释放资源
            fos1.close();
        }
    }
    

    可以看出,这次是接着上次的内容继续进行写入的
    在这里插入图片描述

    🍃3.FileInputStream

    操作本地文件的字节输入流,可以把本地文件中的数据读取到程序中来

    🍁3.1每次读取一个字节

    在这里插入图片描述

    第一步也是创建对象,接着调用read()方法,就可以读取到一个字节的内容,读到的内容也是ASCII码对应的数字

    public class ByteStreamDemo2 {
        public static void main(String[] args) throws IOException {
            //字节输出入流,如果文件不存在,就会报错
            FileInputStream fis = new FileInputStream("E:\\java\\a.txt");
            //读取一个字节,读取到末尾再继续读会返回-1
            int res = fis.read();
            System.out.println((char) res);
            //释放资源
            fis.close();
        }
    }
    

    在这里插入图片描述
    创建对象时,如果对应路径不存在,就会直接报错,此外,读取到末尾之后继续读就会返回-1,那么文件中最后确实是-1的话怎么判断呢?“-1"其实是分为”-" 和 "1"的,所以并不冲突
    根据这个特性可以进行文件的循环读取

    		int a = 0;
            while ((a = fis.read() )!= -1){
                System.out.print((char)a);
            }
            System.out.println();
    

    问题:如果不用一个变量来接收行不行?

            while(fis.read() != -1){
                System.out.println((char)fis.read());
            }
    

    答:因为每次调用read就表示往后移动一位,所以每次循环都进行了两次读取(判断条件一次,输出语句一次),打印的数据其实是跳跃的

    🍁3.2读取多个字节

    如果要读取多个字节,可以在read方法中传入一个byte类型的数组,数组长度是多少每次就读几个字节

    public class ByteStreamDemo2 {
        public static void main(String[] args) throws IOException {
            //字节输出入流,如果文件不存在,就会报错
            FileInputStream fis = new FileInputStream("E:\\java\\a.txt");
            //读取多个字节
            byte[] byte1 = new byte[3];
            int len1 = fis.read(byte1);
            System.out.println(new String(byte1));
            System.out.println(len1);
    
            //如果继续往下读,因为文件中剩余的数据不足数组的长度,只覆盖读取到了的数据
            int len2 = fis.read(byte1);
            System.out.println(new String(byte1));
            System.out.println(new String(byte1,0,len2));//只打印读到的数据
            System.out.println(len2);
            //释放资源
            fis.close();
        }
    }
    

    如果继续往下读,文件中剩余的数据不足数组的长度,只覆盖读取到的数据,此时就可以把读取的字节数进行一个返回,只打印读取到的数据,也就是没有被覆盖的数据不打印
    在这里插入图片描述

    🍃文件拷贝

    文件拷贝就是把读取和写入结合起来,把读取到的数据再写入另一个文件中,所以也有两种方式进行拷贝,一种是一个字节一个字节的拷贝,另一种就是直接定义一个大容量的数组,一次拷贝完成,很显然,后者更加高效

    public class ByteStreamDemo3 {
        public static void main(String[] args) throws IOException {
            FileInputStream fis = new FileInputStream("E:\\java\\a.txt");
            FileOutputStream fos = new FileOutputStream("E:\\java\\b.txt");
    
            //一次拷贝一个字节
            int b1 = 0;
            while ((b1 = fis.read()) != -1) {
                fos.write(b1);
            }
    
            //一次拷贝多个字节
            byte[] b2 = new byte[1024];
            int len = 0;
            while((len = fis.read(b2)) != -1){
                fos.write(b2,0,len);
            }
            //释放资源,先开后关
            fos.close();
            fis.close();
        }
    }
    

    最后释放资源的时候需要注意,遵循最先打开的文件最后关闭的原则

    🍃IO流中的异常处理方式

    在之前,我们都是对异常进行抛出处理,怎么去使用try - catch处理呢?
    首先需要明白,程序最后都要进行资源释放,所以就可以采用try - catch - finally结构,把资源释放的模块放在finally里
    在这里插入图片描述
    如果按照正常的想法,把有异常的模块都放进try里,此时创建出的对象就属于局部变量,finally里调用不了,就需要把创建对象的部分写在外面
    在这里插入图片描述
    但此时还是报错了,还需要对finally的内容进行异常处理
    在这里插入图片描述
    这样看貌似是没有问题了,但是还是有一个细节需要注意,如果创建对象时给的路径不存在,还是会报错,除了正常给出的路径异常,还有一个空指针异常
    在这里插入图片描述
    就需要处理对象为空的情况

    public class ByteStreamDemo4 {
        public static void main(String[] args) {
            FileInputStream fis = null;
            FileOutputStream fos = null;
            try {
                fis = new FileInputStream("E:\\java\\a.txt");
                fos = new FileOutputStream("E:\\java\\b.txt");
                //一次拷贝多个字节
                byte[] b = new byte[1024];
                int len = 0;
                while ((len = fis.read(b)) != -1) {
                    fos.write(b, 0, len);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                //释放资源,先开后关
                if (fos != null) {
                    try {
                        fos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (fis != null) {
                    try {
                        fis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    

    此时再运行就没有空指针异常了
    上面的代码看起来很多,在JDK7和JDK9种给出了两种简化版本,推出了AutoCloseable接口,它定义了一个可以被自动关闭的资源,确保在 try 代码块执行完毕后,资源能够自动关闭,即使发生了异常,但是只能在特定的情况可以使用
    JDK7:
    在这里插入图片描述
    JDK9:
    在这里插入图片描述
    这样就不用在finally种写一堆对释放资源处理的异常了,不过,一般情况下直接抛出就可以了

  • 相关阅读:
    Springboot毕业设计毕设作品,微信校园疫情防控小程序设计与实现
    Java异常
    mysql学习--binlog与gtid主从同步
    synchronized下的 i+=2 和 i++ i++执行结果居然不一样
    【老生谈算法】matlab实现香农编码源码——香农编码
    今抖云创—短视频需要的那些自媒体工具
    小程序开发直传腾讯云操作步骤
    前端面经 强缓存与协商缓存
    代理IP和Socks5代理:跨界电商与全球爬虫的关键技术
    视频增强和修复工具 Topaz Video AI mac中文版功能
  • 原文地址:https://blog.csdn.net/2202_76097976/article/details/140061317