Java IO流全面教程

此笔记来自于B站黑马程序员

File

创建对象

image-20241005222459829

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(pathname: "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");
    }
}
  • File对象既可以代表文件、也可以代表文件夹。
  • File封装的对象仅仅是一个路径名,这个路径可以是存在的,也允许是不存在的。

image-20241005225438100

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

image-20241005223959659

就不演示代码了,Java 有一个很好的优势,即见名知意思

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

/***
** 目标:掌握 File 的创建和删除文件相关的
**/
public class FileTest3 {
    public static void main(String[] args) {
        // 1.public boolean createFile(); 创建一个新文件(文件内容为空), 创建成功返回true, 反之
        File f1 = new File("D:/resurce/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());
        
        // 4.public boolean delete() 删除文件,或者空文件,注意:不能删除非空文件夹
        System.out.println(f1.delete());
        System.out.println(f2.delete());
        File f4 = new File("D:/resource");
        System.out.println(f4.delete());
    }
}

delete方法默认只能删除文件和空文件夹,删除文件后的文件不会进入回收站

常用方法3:遍历文件夹

public class FilleTest4 {
    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 f = new File("D:/resource/aaa");
        File[] files1 = f.listFiles();
        System.out.println(Arrays.toString(files1));
    }
}
使用 listFiles 方法时的注意事项:
  • 当主调是文件,或者路径不存在时,返回null
  • 当主调是空文件夹时,返回一个长度为0的数组
  • 当主调是一个有内容的文件夹时,将里面所有一级文件和文件夹的路径放在File数组中返回
  • 当主调是一个文件夹,且里面有隐藏文件时,将里面所有文件和文件夹的路径放在File数组中返回,包含隐藏文件
  • 当主调是一个文件夹,但是没有权限访问该文件夹时,返回null

前置知识:方法递归

什么是方法递归?

递归是一种算法,在程序设计语言中广泛应用。

从形式上说:方法调用自身的形式称为方法递归(recursion)

递归的形式

直接递归:方法自己调用自己。

间接递归:方法调用其他方法,其他方法又回调方法自己。

使用方法递归时需要注意的问题:

递归如果没有控制好终止,会出现递归死循环,导致栈内存溢出错误。

文件搜素

image-20241005231038801

package com.itheima.d2_recursion

import java.io.File;

public class RecursionTest3 {
    public static void main(String[] args) {
        searchFile(new File("D:/"), "QQ.exe");
    }
    /**
    * 去目录下搜索某个文件
    * @param dir 目录
    * @param fileName 要搜索的文件名称
    */
    public static void searchFile(File dir, String fileName) {
        // 1.把非法的情况都拦截住
        if (dir == null || !dir.exists() || dir.isFile()) {
            reutrn;
        }
        
        // 2.dir不是null,存在,一定是目录对象
        // 获取当前目录下的全部一级文件对象
        File[] files = dir.listFiles();
        
        // 3. 判断当前目录下是否存在一级文件对象,以及是否可以拿到一级文件对象
        if (files != null && files.length > 0) {
			// 4.遍历全部一级文件对象
			for (File f : files) {
                if (f.isFile()) {
                    if (f.getName().contains(fileName)) {
                    	System.out.println("找到了: " + f.getAbsolutePath());
                	}
                } else {
                 	searchFile(f, fileName);   
                }
            }
        }
    }
}

前置知识:字符集

image-20241006002947388

image-20241006003403394

image-20241006003517166

image-20241006003531605

image-20241006134415217

本节要点
  • ASCI字符集:只有英文、数字、符号等,占1个字节。
  • GBK字符集:汉字占2个字节,英文、数字占1个字节。
  • UTF-8字符集:汉字占3个字节,英文、数字占1个字节。

注意1:字符编码时使用的字符集,和解码时使用的字符集必须一致,**否则会出现乱码 **⚠️

注意2:英文,数字一般不会乱码,因为很多字符集都兼容了 ASCII 编码。 ⚠️

image-20241006134944825

import java.util.Arrays;

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);
        System.out.println(s1);
        
        String s2 = new String(bytes1, "GBK");
        System.out.println(s2);
    }
}

IO 流

image-20241006140113709

IO 流的应用场景

image-20241006140335209

IO 流概述

image-20241006140806697

IO流-字节流

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

image-20241006141529213

public class FileInputStreamTest1 {
    public static void main(String[] args) throws Exception {
        // 1. 创建文件字节输入流管道,与源文件接通
        // InpustStream 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);
        int b;
        while ((b = is.read()) != -1) {
			System.out.print((char) b);
        }
        
        // 读取的性能很差
        // 读取汉字会乱码
        
        // 流使用完毕后,必须关闭,释放系统资源
        is.close();
    }
}
public class FileInputStreamTest1 {
    public static void main(String[] args) throws Exception {
        // 1. 创建文件字节输入流管道,与源文件接通
        // InpustStream 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(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
        
        is.close();
    }
}

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

public class FileInputStreamTest1 {
    public static void main(String[] args) throws Exception {
        // 1. 创建文件字节输入流管道,与源文件接通
        // InpustStream is = new FileInputStream(new File("file-io-app\\src\\itheima01.txt"));
        
        // 简化写法,推荐使用
		InputStream is = new FileInputStream(("file-io-app\\src\\itheima01.txt"));
        
        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(); // 关闭流
    }
}

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

文件字节输入流:一次读取完全部字节
  • 方式一: 自己定义一个字节数组与被读取的文件大小一样大,然后使用该字节数组,一次读完文件的全部字节。
  • image-20241006145641914
public class FileInputStreamTest1 {
    public static void main(String[] args) throws Exception {
        // 1. 创建文件字节输入流管道,与源文件接通
        // InpustStream is = new FileInputStream(new File("file-io-app\\src\\itheima01.txt"));
        
        // 简化写法,推荐使用
		InputStream is = new FileInputStream(("file-io-app\\src\\itheima01.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);
        
        is.close(); // 关闭流
    }
}
方式二:Java官方为lnputStream提供了如下方法,可以直接把文件的全部字节读取到一个字节数组中返回。

image-20241006150532012

public class FileInputStreamTest1 {
    public static void main(String[] args) throws Exception {
        // 1. 创建文件字节输入流管道,与源文件接通
        // InpustStream is = new FileInputStream(new File("file-io-app\\src\\itheima01.txt"));
        
        // 简化写法,推荐使用
		InputStream is = new FileInputStream(("file-io-app\\src\\itheima01.txt"));
       
        byte[] buffer = is.readAllBytes();
        System.out.println(new String(buffer));
        is.close(); // 关闭流
    }
}
总结

image-20241006150614013

文件字节输出流:写字节出去 (FileWriter)

作用:以内存为基准,把内存中的数据以字节的形式写出到文件中去。

image-20241006151008372

public class FileOutputStreamTest4 {
    public static void main(String[] args) throws Exception {
        //1、创建一个字节输出流管道与目标文件接通。
        //覆盖管道:覆盖之前的数据
        
       // OutputStream os =
       //     new File0utputStream("file-io-app/src/itheima04out.txt");
        
        //追加数据的管道
        OutputStream os =
            new File0utputStream(name:"file-io-app/src/itheima04out.txt", append:true);
        
        //2、开始写字节数据出去了
        os.write(97); //97 就是一个字节,代表 a
        os.write('b'); //‘b'也是一个字节
        //os.write('磊');//[ooo]默认只能写出去一个字节
        
        byte[] bytes = "我爱你中国abc".getBytes();
        os.write(bytes);
        
        os.write(bytes, off:0, len:15);
        
        os.close()//关闭流
    }
}

案例:文件复制

image-20241006152027887

public class FileOutputStreamTest4 {
    public static void main(String[] args) throws Exception {
        // 复制文件
		InputStream is = new FileInputStream("file-io-app\\src\\itheima03.txt");
        
        // 2.创建一个字节输出流管道与目标文件接通
        OutputStream os = new FileOutputStream("file-io-app\\src\\itheima03copy.txt");
        
        // 1024 * 1024 + 6;
        // 3.创建要给字节数组,负责转移字节数组
        byte[] buffer = new byte[1024]; // 1kb
        int lne;
        while ((len == is.read(buffer)) != -1) {
            os.write(buffer, 0, len);
        }
        
        os.close();
        is.close();
        System.out.println("复制完成!!!");
    }
}

IO流-资源释放方式

  • finally 代码区的特点:无论 try 中的程序是正常执行了,还是出现了异常,最后都一定会执行 finally区,除非JVM终止。

作用:一般用于在程序执行完成后进行资源的释放操作**(专业级做法)。**

public class Test1 {
    public static void main(String[] args) {
        try {
            System.out.println
上一篇:深度学习中的损失函数详解


下一篇:AI 改写数学竞赛 | 从 IMO Grand 到 AlphaProof-AI 与 IMO 竞赛