Java IO流(一)

作者简介:☕️大家好,我是intelligent_M,一个Java后端开发者!
当前专栏:intelligent_M—— Java IO流 ,CSDN博客。

后续会更新Java相关技术栈以及链表哈希表二叉树…,回溯算法贪心算法…等等算法题。
创作不易 欢迎点赞评论!!!


File

创建对象

  • 创建File类的对象
    在这里插入图片描述
  • 第一个构造器是最常用的
  • 注意:File对象既可以代表文件,也可以代表文件夹
  • File封装的对象仅仅是一个路径名,这个路径可以是存在的,也允许是不存在的
  • 绝对路径:从盘符开始
    在这里插入图片描述
  • 相对路径:不带盘符,默认直接到当前工程下的目录寻找文件
    在这里插入图片描述
/**
 * 目标:掌握File创建对象,代表具体文件的方案。
 */
public class FileTest1 {
    public static void main(String[] args) {
        // 1、创建一个File对象,指代某个具体的文件。
        // 路径分隔符
        // File f1 = new File("D:/resource/ab.txt");
        // File f1 = new File("D:\\resource\\ab.txt");
        File f1 = new File("D:" + File.separator +"resource" + File.separator + "ab.txt");
        System.out.println(f1.length()); // 文件大小

        File f2 = new File("D:/resource");
        System.out.println(f2.length());

        // 注意:File对象可以指代一个不存在的文件路径
        File f3 = new File("D:/resource/aaaa.txt");
        System.out.println(f3.length());
        System.out.println(f3.exists()); // false

        // 我现在要定位的文件是在模块中,应该怎么定位呢?
        // 绝对路径:带盘符的
        // File f4 = new File("D:\\code\\javasepromax\\file-io-app\\src\\itheima.txt");
        // 相对路径(重点):不带盘符,默认是直接去工程下寻找文件的。
        File f4 = new File("file-io-app\\src\\itheima.txt");
        System.out.println(f4.length());
    }
}

常用方法1:判断文件类型,获取文件信息

  • File提供的判断文件类型,获取文件信息功能
    在这里插入图片描述
/**
     目标:掌握File提供的判断文件类型、获取文件信息功能
 */
public class FileTest2 {
    public static void main(String[] args) throws UnsupportedEncodingException {
        // 1.创建文件对象,指代某个文件
        File f1 = new File("D:/resource/ab.txt");
        //File f1 = new File("D:/resource/");

        // 2、public boolean exists():判断当前文件对象,对应的文件路径是否存在,存在返回true.
        System.out.println(f1.exists());

        // 3、public boolean isFile() : 判断当前文件对象指代的是否是文件,是文件返回true,反之。
        System.out.println(f1.isFile());

        // 4、public boolean isDirectory()  : 判断当前文件对象指代的是否是文件夹,是文件夹返回true,反之。
        System.out.println(f1.isDirectory());

        // 5.public String getName():获取文件的名称(包含后缀)
        System.out.println(f1.getName());

        // 6.public long length():获取文件的大小,返回字节个数
        System.out.println(f1.length());

        // 7.public long lastModified():获取文件的最后修改时间。
        long time = f1.lastModified();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        System.out.println(sdf.format(time));

        // 8.public String getPath():获取创建文件对象时,使用的路径
        File f2 = new File("D:\\resource\\ab.txt");
        File f3 = new File("file-io-app\\src\\itheima.txt");
        System.out.println(f2.getPath());
        System.out.println(f3.getPath());

        // 9.public String getAbsolutePath():获取绝对路径
        System.out.println(f2.getAbsolutePath());
        System.out.println(f3.getAbsolutePath());
    }
}

常用方法2:创建文件,删除文件

  • File类创建文件的功能
    在这里插入图片描述
  • File类删除文件的功能
    在这里插入图片描述
  • 注意:delete方法默认只能删除文件和空文件夹,删除后的文件不会进入回收站
/**
 * 目标:掌握File创建和删除文件相关的方法。
 */
public class FileTest3 {
    public static void main(String[] args) throws Exception {
        // 1、public boolean createNewFile():创建一个新文件(文件内容为空),创建成功返回true,反之。
        File f1 = new File("D:/resource/itheima2.txt");
        System.out.println(f1.createNewFile());

        // 2、public boolean mkdir():用于创建文件夹,注意:只能创建一级文件夹
        File f2 = new File("D:/resource/aaa");
        System.out.println(f2.mkdir());

        // 3、public boolean mkdirs():用于创建文件夹,注意:可以创建多级文件夹
        File f3 = new File("D:/resource/bbb/ccc/ddd/eee/fff/ggg");
        System.out.println(f3.mkdirs());

        // 3、public boolean delete():删除文件,或者空文件,注意:不能删除非空文件夹。
        System.out.println(f1.delete());
        System.out.println(f2.delete());
        File f4 = new File("D:/resource");
        System.out.println(f4.delete());
    }
}

常用方法3:遍历文件夹

  • File类提供的遍历文件夹的功能
    在这里插入图片描述
  • 使用listFiles方法时的注意事项:
    • 当主调是文件,或者路径不存在时,返回null
    • 当主调是空文件夹时,返回一个长度为0的数组
    • 当主调是一个有内容的文件夹时,将里面所有的一级文件和文件夹的路径放在File数组中返回
    • 当主调是一个文件夹,且里面有隐藏文件时,将里面所有文件和文件夹的路径放在Fule数组中返回,包含隐藏文件
    • 当主调是一个文件夹,但是没有权限访问该文件夹,返回null
/**
 * 目标:掌握File提供的遍历文件夹的方法。
 */
public class FileTest4 {
    public static void main(String[] args) {
        // 1、public String[] list():获取当前目录下所有的"一级文件名称"到一个字符串数组中去返回。
        File f1 = new File("D:\\course\\待研发内容");
        String[] names = f1.list();
        for (String name : names) {
            System.out.println(name);
        }

        // 2、public File[] listFiles():(重点)获取当前目录下所有的"一级文件对象"到一个文件对象数组中去返回(重点)
        File[] files = f1.listFiles();
        for (File file : files) {
            System.out.println(file.getAbsolutePath());
        }

        File f = new File("D:/resource/aaa");
        File[] files1 = f.listFiles();
        System.out.println(Arrays.toString(files1));
    }
}

前置知识

方法递归

认识递归的形式

  • 什么是方法递归?
    • 递归是一种算法,在程序设计语言中广泛应用
    • 从形式上说:方法调用自身的形式称为方法递归(recursion)
  • 递归的形式
    • 直接递归:方法自己调用自己
    • 间接递归:方法调用其他方法,其他方法又回调方法自己
  • 使用方法递归时需要注意的问题:
    • 递归如果没有控制好终止,会出现递归死循环,导致栈内存溢出错误
/**
 * 目标:认识一下递归的形式。
 */
public class RecursionTest1 {
    public static void main(String[] args) {
        test1();
    }

    // 直接方法递归
    public static void test1(){
        System.out.println("----test1---");
        test1(); // 直接方法递归
    }

    // 间接方法递归
    public static void test2(){
        System.out.println("---test2---");
        test3();
    }

    public static void test3(){
        test2(); // 间接递归
    }
}

应用,执行流程,算法思想

  • 案例:计算n的阶乘
    在这里插入图片描述

  • 递归算法三要素:
    在这里插入图片描述

/**
 * 目标:掌握递归的应用,执行流程和算法思想。
 */
public class RecursionTest2 {
    public static void main(String[] args) {
        System.out.println("5的阶乘是:" + f(5));
    }

    public static int f(int n){
        // 终结点
        if(n == 1){
            return 1;
        }else {
            return f(n - 1) * n;
        }
    }
}

其他应用:文件搜索

在这里插入图片描述

/**
 * 目标:掌握文件搜索的实现。
 */
public class RecursionTest3 {
    public static void main(String[] args) throws Exception {
          searchFile(new File("D:/") , "QQ.exe");
    }

    /**
     * 去目录下搜索某个文件
     * @param dir  目录
     * @param fileName 要搜索的文件名称
     */
    public static void searchFile(File dir, String fileName) throws Exception {
        // 1、把非法的情况都拦截住
        if(dir == null || !dir.exists() || dir.isFile()){
            return; // 代表无法搜索
        }

        // 2、dir不是null,存在,一定是目录对象。
        // 获取当前目录下的全部一级文件对象。
        File[] files = dir.listFiles();

        // 3、判断当前目录下是否存在一级文件对象,以及是否可以拿到一级文件对象。
        if(files != null && files.length > 0){
            // 4、遍历全部一级文件对象。
            for (File f : files) {
                // 5、判断文件是否是文件,还是文件夹
                if(f.isFile()){
                    // 是文件,判断这个文件名是否是我们要找的
                    if(f.getName().contains(fileName)){
                        System.out.println("找到了:" + f.getAbsolutePath());
                        Runtime runtime = Runtime.getRuntime();
                        runtime.exec(f.getAbsolutePath());
                    }
                }else {
                    // 是文件夹,继续重复这个过程(递归)
                    searchFile(f, fileName);
                }
            }
        }
    }
}

字符集

常见字符集介绍

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

  • 标准ASCII字符集
  • ASCII(American Standard Code for Information Interchange):美国信息交换标准代码,包括了英文,符号等
  • 标准ASCII使用一个字节存储一个字符,首位是0,总共可表示128个字符,对美国来说完全够用
  • 中国用GBK(汉字内码扩展规范,国标)
  • 汉字编码字符集,包含了2万多个汉字字符,GBK中一个中文字符编码成两个字节的形式存储
  • 注意:GBK兼容了ASCII字符集
    在这里插入图片描述
  • Unicode字符集(统一码,也叫万国码)
  • Unicode是国际组织制定的,可以容纳世界上所有文字,符号的字符集
    在这里插入图片描述
  • UTF-8是Unicode字符集的一种编码方案,采取可变长编码方案,共分四个长度区:1个字节,2个字节,3个字节,4个字节
  • 英文字符,数字等只占一个字节(兼容标准ASCII编码),汉字字符占用3个字节
    在这里插入图片描述
  • 注意:技术人员在开发时都应该使用UTF-8编码
  • ASCII字符集:只有英文,数字,符号等,占1个字节
  • GBK字符集:汉字占2个字节,英文,数字占1个字节
  • UTF-8字符集:汉字占3个字节,英文,数字占1个字节
  • 注意1:字符编码时使用的字符集,和解码时使用的字符集必须一致,否则会出现乱码
  • 注意2:英文,数字一般不会乱码,因为很多字符集都兼容了ASCII编码

字符集的编码,解码操作

  • Java代码完成对字符的编码
    在这里插入图片描述
  • Java代码完成对字符的解码
    在这里插入图片描述
/**
 * 目标:掌握如何使用Java代码完成对字符的编码和解码。
 */
public class Test {
    public static void main(String[] args) throws Exception {
        // 1、编码
        String data = "a我b";
        byte[] bytes = data.getBytes(); // 默认是按照平台字符集(UTF-8)进行编码的。
        System.out.println(Arrays.toString(bytes));

        // 按照指定字符集进行编码。
        byte[] bytes1 = data.getBytes("GBK");
        System.out.println(Arrays.toString(bytes1));

        // 2、解码
        String s1 = new String(bytes); // 按照平台默认编码(UTF-8)解码
        System.out.println(s1);

        String s2 = new String(bytes1, "GBK");
        System.out.println(s2);
    }
}

IO流

IO流概述

  • io流输入输出流,读写数据的
    在这里插入图片描述

IO流的应用场景

在这里插入图片描述

怎么学IO流

  • 怎么学IO流
    • 1.先搞清楚IO流的分类,体系
    • 2.再挨个学习每个IO流的作用,用法

IO流的分类

  • 按流的方向分为:输入流和输出流
    在这里插入图片描述-
  • 按流中数据的最小单位,分为字节流和字符流
    在这里插入图片描述- IO流总体来看就有四大流
  • 字节输入流:以内存为基准,来自磁盘文件/网络中的数据以字节的形式读入到内存中去的流
  • 字节输出流:以内存为基准,把内存中的数据以字节写出到磁盘文件或者网络中去的流
  • 字符输入流:以内存为基准,来自磁盘文件/网络中的数据以字符的形式读入到内存中去的流
  • 字符输出流:以内存为基准,把内存中的数据以字符写出到磁盘文件或者网络介质中去的流
    在这里插入图片描述
  • IO流的体系(Java.io包下的)
    在这里插入图片描述

IO流- 字节流

文件字节输入流:每次读取一个字节

  • FileInputStream(文件字节输入流)
  • 作用:以内存为基准,来自磁盘文件/网络中的数据以字节的形式读入到内存中去
    在这里插入图片描述在这里插入图片描述
    在这里插入图片描述
  • 注意事项:使用FileInputStream每次读取一个字节,读取性能较差,并且读取汉字输出还会出现乱码且无法避免
/**
 * 目标:掌握文件字节输入流,每次读取一个字节。
 */
public class FileInputStreamTest1 {
    public static void main(String[] args) throws Exception {
        // 1、创建文件字节输入流管道,与源文件接通。
        // InputStream is = new FileInputStream(new File("file-io-app\\src\\itheima01.txt"));
        // 简化写法:推荐使用。
        InputStream is = new FileInputStream(("file-io-app\\src\\itheima01.txt"));

        // 2、开始读取文件的字节数据。
        // public int read():每次读取一个字节返回,如果没有数据了,返回-1.
//        int b1 = is.read();
//        System.out.println((char)b1);
//
//        int b2 = is.read();
//        System.out.println((char) b2);
//
//        int b3 = is.read();
//        System.out.println(b3);

        // 3、使用循环改造上述代码
        int b; // 用于记住读取的字节。
        while ((b = is.read()) != -1){
            System.out.print((char) b);
        }

        // 读取数据的性能很差!
        // 读取汉字输出会乱码!!无法避免的!!
        // 流使用完毕之后,必须关闭!释放系统资源!
        is.close();
    }
}

文件字节输入流:每次读取多个字节

  • 使用FileInputStream每次读取多个字节,读取性能得到了提升,但读取汉字输出还是会乱码
/**
 * 目标:掌握使用FileInputStream每次读取多个字节。
 */
public class FileInputStreamTest2 {
    public static void main(String[] args) throws Exception {
        // 1、创建一个字节输入流对象代表字节输入流管道与源文件接通。
        InputStream is = new FileInputStream("file-io-app\\src\\itheima02.txt");

        // 2、开始读取文件中的字节数据:每次读取多个字节。
        //  public int read(byte b[]) throws IOException
        //  每次读取多个字节到字节数组中去,返回读取的字节数量,读取完毕会返回-1.
//        byte[] buffer = new byte[3];
//        int len = is.read(buffer);
//        String rs = new String(buffer);
//        System.out.println(rs);
//        System.out.println("当次读取的字节数量:" + len);
//
//        // buffer = [abc]
//        // buffer = [66c]
//        int len2 = is.read(buffer);
//        // 注意:读取多少,倒出多少。
//        String rs2 = new String(buffer, 0, len2);
//        System.out.println(rs2);
//        System.out.println("当次读取的字节数量:" + len2);
//
//        int len3 = is.read(buffer);
//        System.out.println(len3); // -1

        // 3、使用循环改造。
        byte[] buffer = new byte[3];
        int len; // 记住每次读取了多少个字节。  abc 66
        while ((len = is.read(buffer)) != -1){
            // 注意:读取多少,倒出多少。
            String rs = new String(buffer, 0 , len);
            System.out.print(rs);
        }
        // 性能得到了明显的提升!!
        // 这种方案也不能避免读取汉字输出乱码的问题!!

        is.close(); // 关闭流
    }
}

文件字节输入流:一次读取完全部字节

  • 使用字节流读取中文,如何保证输出不乱码,怎么解决?
  • 定义一个与文件一样大的字节数组,一次性读取完文件的全部字节
  • 方法一:自己定义一个字节数组与被读取的文件大小一样大,人后使用该字节数组,一次性读完文件的全部字节
    在这里插入图片描述
  • 方式二:Java官方为InputStream提供了如下方法,可以直接把文件的全部字节读取到一个字节数组中返回
    在这里插入图片描述
  • 直接把文件数据全部读取到一个字节数组可以避免乱码,但是也存在问题
  • 如果文件过大,创建的字节数组也会过大,可能引起内存溢出
  • 读写文本内容更适合用字符流
  • 字节流适合做数据的转移,如:文件复制等

/**
 * 目标:使用文件字节输入流一次读取完文件的全部字节。
 */
public class FileInputStreamTest3 {
    public static void main(String[] args) throws Exception {
        // 1、一次性读取完文件的全部字节到一个字节数组中去。
        // 创建一个字节输入流管道与源文件接通
        InputStream is = new FileInputStream("file-io-app\\src\\itheima03.txt");

        // 2、准备一个字节数组,大小与文件的大小正好一样大。
//        File f = new File("file-io-app\\src\\itheima03.txt");
//        long size = f.length();
//        byte[] buffer = new byte[(int) size];
//
//        int len = is.read(buffer);
//        System.out.println(new String(buffer));
//
//        System.out.println(size);
//        System.out.println(len);

        byte[] buffer = is.readAllBytes();
        System.out.println(new String(buffer));

        is.close(); // 关闭流
    }
}

文件字节输出流:写字节出去

  • FileOutputStream(文件字节输出流)
  • 作用:以内存为基准,把内存中的数据以字节的形式写出到文件中去
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
/**
 * 目标:掌握文件字节输出流FileOutputStream的使用。
 */
public class FileOutputStreamTest4 {
    public static void main(String[] args) throws Exception {
        // 1、创建一个字节输出流管道与目标文件接通。
        // 覆盖管道:覆盖之前的数据
//        OutputStream os =
//                new FileOutputStream("file-io-app/src/itheima04out.txt");

        // 追加数据的管道
        OutputStream os =
                new FileOutputStream("file-io-app/src/itheima04out.txt", true);

        // 2、开始写字节数据出去了
        os.write(97); // 97就是一个字节,代表a
        os.write('b'); // 'b'也是一个字节
        // os.write('磊'); // [ooo] 默认只能写出去一个字节

        byte[] bytes = "我爱你中国abc".getBytes();
        os.write(bytes);

        os.write(bytes, 0, 15);

        // 换行符
        os.write("\r\n".getBytes());

        os.close(); // 关闭流
    }
}

案例:文件复制

  • 字节流非常适合做一切文件的复制操作
  • 任何文件的底层都是字节,字节流做复制,时一字不漏的转移完全部字节,只要复制后的文件格式一致就没有问题
  • 文件复制
    在这里插入图片描述
/**
 * 目标:使用字节流完成对文件的复制操作。
 */
public class CopyTest5 {
    public static void main(String[] args) throws Exception {
        // 需求:复制照片。
        // 1、创建一个字节输入流管道与源文件接通
        InputStream is = new FileInputStream("file-io-app\\src\\itheima03.txt");
        // 2、创建一个字节输出流管道与目标文件接通。
        OutputStream os = new FileOutputStream("file-io-app\\src\\itheima03copy.txt");

        System.out.println(10 / 0);
        // 3、创建一个字节数组,负责转移字节数据。
        byte[] buffer = new byte[1024]; // 1KB.
        // 4、从字节输入流中读取字节数据,写出去到字节输出流中。读多少写出去多少。
        int len; // 记住每次读取了多少个字节。
        while ((len = is.read(buffer)) != -1){
            os.write(buffer, 0, len);
        }

        os.close();
        is.close();
        System.out.println("复制完成!!");
    }
}

IO流-资源释放的方式

try-catch-finally

在这里插入图片描述

  • finally代码区的特点:无论try中的程序是正常执行了,还是出现了异常,最后都一定会执行finally区,除非JVM终止
  • 作用:一般用于再程序执行完成之后进行资源的释放操作(专业级做法)
  • 缺点:臃肿,不优雅
    在这里插入图片描述
/**
 * 目标:认识try-catch-finally。
 */
public class Test1 {
    public static void main(String[] args) {
        try {
            System.out.println(10 / 2);
            // return; // 跳出方法的执行
            // System.exit(0); // 虚拟机
        }catch (Exception e){
            e.printStackTrace();
        } finally {
            System.out.println("===finally执行了一次===");
        }

        System.out.println(chu(10, 2));
    }

    public static int chu(int a, int b){
        try {
            return a / b;
        }catch (Exception e){
            e.printStackTrace();
            return -1; // 代表的是出现异常
        }finally {
            // 千万不要在finally中返回数据!
            return 111;
        }
    }
}
  • 掌握释放资源的方式

/**
 * 目标:掌握释放资源的方式。
 */
public class Test2 {
    public static void main(String[] args)  {
        InputStream is = null;
        OutputStream os = null;
        try {
            System.out.println(10 / 0);
            // 1、创建一个字节输入流管道与源文件接通
            is = new FileInputStream("file-io-app\\src\\itheima03.txt");
            // 2、创建一个字节输出流管道与目标文件接通。
            os = new FileOutputStream("file-io-app\\src\\itheima03copy.txt");

            System.out.println(10 / 0);

            // 3、创建一个字节数组,负责转移字节数据。
            byte[] buffer = new byte[1024]; // 1KB.
            // 4、从字节输入流中读取字节数据,写出去到字节输出流中。读多少写出去多少。
            int len; // 记住每次读取了多少个字节。
            while ((len = is.read(buffer)) != -1){
                os.write(buffer, 0, len);
            }
            System.out.println("复制完成!!");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 释放资源的操作
            try {
                if(os != null) os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(is != null) is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

try-with-resource

  • JDK7开始提供了更简单的资源释放方案:try-with-resource
    在这里插入图片描述
  • 该资源使用完毕后,会自动调用其他close()方法,完成对资源的释放
  • ()中只能放置资源,否则报错
  • 什么是资源呢?
  • 资源一般指的是最终实现了AutoCloseable接口
    在这里插入图片描述

/**
 * 目标:掌握释放资源的方式:try-with-resource
 */
public class Test3 {
    public static void main(String[] args)  {
        try (
                // 1、创建一个字节输入流管道与源文件接通
                InputStream is = new FileInputStream("file-io-app\\src\\itheima03.txt");
                // 2、创建一个字节输出流管道与目标文件接通。
                OutputStream os = new FileOutputStream("file-io-app\\src\\itheima03copy.txt");

                // 注意:这里只能放置资源对象。(流对象)
                // int age = 21;
                // 什么是资源呢?资源都是会实现AutoCloseable接口。资源都会有一个close方法,并且资源放到这里后
                // 用完之后,会被自动调用其close方法完成资源的释放操作。
                MyConnection conn = new MyConnection();//自定义的一个资源类
                ){

            // 3、创建一个字节数组,负责转移字节数据。
            byte[] buffer = new byte[1024]; // 1KB.
            // 4、从字节输入流中读取字节数据,写出去到字节输出流中。读多少写出去多少。
            int len; // 记住每次读取了多少个字节。
            while ((len = is.read(buffer)) != -1){
                os.write(buffer, 0, len);
            }
            System.out.println(conn);
            System.out.println("复制完成!!");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
  • Myconnection类
public class MyConnection implements AutoCloseable{
    @Override
    public void close() throws Exception {
        System.out.println("释放了与某个硬件的链接资源~~~~");
    }
}

  • 9
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Intelligent_M

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

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

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

打赏作者

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

抵扣说明:

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

余额充值