文件IO万字超详细解析,文件系统操作,字节流、字符流使用,文件搜索,文件复制解析

文件操作和IO InputStream 是一个抽象类,不能创建实例,所以我们可以实例化它的子类FileInputStream(字节内容更习惯采用十六进制表示)方法修饰符及返回值类型 ⽅法名 说明int read() 一次读取一个字节,返回 -1 代表已经完全读完了int read(byte[] b) 一个参数版本,尝试把这个参数中的字节数组填满int read(byte[] b, int off, int len) 最多读取 len - off 字节的数据到 b中,从 off 开始,返回实际读到的数量。 阅读详情

前言

hello hello💕,这里是洋不写bug~😄,欢迎大家点赞👍👍,关注😍😍,收藏🌹🌹
文件IO就是通过代码对文件进行读写操作,这部分内容主要是概念上的东西比较多,理解起来比较简单,目录1和2的内容,铁汁们大概看下即可,重点是第3部分的内容,要掌握字节流和字符流对文件的读写操作
在这里插入图片描述🎆个人主页:洋不写bug的博客
🎆所属专栏:JavaEE学习
🎆铁汁们对于JavaEE的各种常用核心语法,都可以在上面的JavaEE专栏学习,专栏正在持续更新中🏀,有问题可以写在评论区或者私信我哦~

1,基础知识

文件在计算机中是保存在硬盘上的,操作系统把硬盘操作进行了抽象封装,编程的时候,不会直接操作硬盘,而是通过“文件”的概念,进行间接的操作

在计算机中,是通过文件资源管理器来管理文件的,就类似于用树形结构来进行管理
如下图,就拿博主电脑来举例,在此电脑下有三个盘,每个盘里面有很多目录,每个目录(文件夹)又有目录和文件

在这里插入图片描述



可以通过路径来描述文件的位置,例如E:\jdk\lib\security,文件路径的每一级目录,都用 \ (反斜杠)隔开

在这里插入图片描述

这种以盘符(例如C、D、E盘)开头的,就是绝对路径;计算机中的每个文件的绝对路径是唯一的
其他的操作系统,例如Linux,MacOS,Android,都是采用 / (正斜杠)
Windows虽然默认是\ (反斜杠),但是也是可以识别正斜杠的



除了绝对路径,还有另一种表示方法,就是相对路径,相对路径通常是以. 或者…开头的,相对路径需要有一个参考系,也就是以哪个目录来进行相对的

例如这里,如果以E:\jdk作为基准路径的话,还是表示前面的security目录的话,相对路径就是.\lib\security,基准路径跟相对路径拼接在一起,就是绝对路径🐵

在这里插入图片描述


使用相对路径也可以表示基准路径的上一层,security目录是在lib目录中,那如果以security为基准路径,如何表示jdk目录中的release文件
可以通过…\表示目录或文件的上一层,这里的表示就是…\release

在这里插入图片描述



文件的种类,可以分为两个大类:

  1. 文本文件,存的都是字符串,必须依赖编码(ASCII,UTF8,GBK),如果是ASCII编码的话,那文件的所有内容全都严格按照 ASCII 编码规则转成字节存储(ASCII表如下图)
  2. 二进制文件,非文字类型的(例如视频,图片),直接存原始数据的字节,不涉及字符编码转译,例如视频,是通过音视频压缩算法标准 来翻译 01 字节,变成画面和声音

分辨一个文件是文本文件,还是二进制文件,最直接的方式就是用记事本打开试一下,如果是正常的文字,就是文本文件,如果是乱码,就是二进制文件
用记事本打开一个.java文件,会发现是正常的,这.java文件就是文本文件

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



用记事本打开一个图片,会发现里面就都是乱码,这是因为图片字节存的是像素、颜色、格式信息;但记事本按 UTF-8/GBK 字符编码

在这里插入图片描述

2,文件系统操作

文件系统操作包括创建文件,删除文件,移动文件,获取文件属性等
对文件进行操作,首先要创建File对象来表示文件的位置,创建时后面传入文件的相对路径或者绝对路径,代码如下:

File file = new File("D://test.txt");

注:在Java中使用反斜杠会被编译为转义字符,例如 \n就会标识为换行,因此,在传入文件的地址时,要不使用正斜杠,要不就使用两个反斜杠 //来表示



用相对路径来表示文件位置时,首先要知道当前的基准路径,使用IDEA的铁汁可以打开IDEA的控制台(左下角),按一下enter键,这里出来的路径就是当前的基准路径,这里博主的基准路径是E盘下的JavaEE目录

在这里插入图片描述



可以用文件对象调用下图中的方法,得到文件的各个路径

在这里插入图片描述



用绝对路径来创建个file,再用file调用这些方法看一下,拿到的父目录的路径也是绝对路径,拿到的文件路径、绝对路径、修饰过的绝对路径都是一样的

package io;

import java.io.File;
import java.io.IOException;

public class Demo1 {
    public static void main(String[] args) throws IOException {
        File file = new File("C:\\Users\\36689\\Desktop\\word文档\\前端\\1.html");
        System.out.println(file.getParent());
        System.out.println(file.getName());
        System.out.println(file.getPath());
        System.out.println(file.getAbsolutePath());
        System.out.println(file.getCanonicalPath());
    }
}

在这里插入图片描述



用相对路径来创建个file,拿到的父目录的路径和文件路径也变成了相对路径的形式,getAbsolutePath()非常有意思,就是用基准路径和相对路径拼接了一下,连中间的点都拼接上了

package io;

import java.io.File;
import java.io.IOException;

public class Demo1 {
    public static void main(String[] args) throws IOException {
        File file = new File(".\\src\\main\\java");
        System.out.println(file.getParent());
        System.out.println(file.getName());
        System.out.println(file.getPath());
        System.out.println(file.getAbsolutePath());
        System.out.println(file.getCanonicalPath());
    }
}

在这里插入图片描述



下图中的方法是判断文件是否存在、是不是某种类型、以及创建,删除文件

在这里插入图片描述

刚刚博主在D盘下创建了一个test.txt文件,可以调用这些方法试一下:

package io;

import java.io.File;
import java.io.IOException;

public class Demo1 {
    public static void main(String[] args) throws IOException {
        File file = new File("D://test.txt");
        System.out.println(file.exists());
        System.out.println(file.isFile());
        System.out.println(file.isDirectory());
    }
}

在这里插入图片描述

铁汁们这里可以再创建一个目录来试下这三个方法,博主就不写了



文件的创建和删除,可以在JavaEE文件夹中创建一个文本文件,如下所示:

package io;

import java.io.File;
import java.io.IOException;

public class Demo1 {
    public static void main(String[] args) throws IOException {
        File file = new File(".//test.txt");
        file.createNewFile();
    }
}

在这里插入图片描述

再写个delete,运行下,就会发现文件被删除了

file.delete();



deleteOnExit就是在JVM结束的时候才删除
写一段代码,用Scanner阻塞一下,也就是只有用户输入,程序才会结束,运行后打开JavaEE目录,会发现test.txt并没有被删除,只有在我们控制台输入,使程序结束,文件才会被删除·

package io;

import java.io.File;
import java.io.IOException;
import java.util.Scanner;

public class Demo1 {
    public static void main(String[] args) throws IOException {
        File file = new File(".//test.txt");
        file.createNewFile();
        file.deleteOnExit();
        Scanner scanner = new Scanner(System.in);
        scanner.next();
    }
}

deleteOnExit这种设计在什么时候会用到呢?
我们日常使用的office就用到了这个设计,这里博主桌面有个Java复习的文档,打开这个文档后,会发现同级目录下生成了一个文件名相同的文件(如下图),当我们正常关闭文件时,这个生成的隐藏文件就会被删除

在这里插入图片描述

这是因为我们对于文件的修改,如果没有保存的话,这些修改都是保存在内存上的,那如果电脑出问题蓝屏,或者断电,那文件没保存的内容就会丢失

为了避免这种情况数据的丢失,office就会在我们打开文件编辑时,把我们的修改保存下来,保存到隐藏文件中,隐藏文件是储存在硬盘中的,只有正常的退出隐藏文件才会被删除,如果是断电或者蓝屏,那隐藏文件就不会删除,再启动的时候,office就会通过隐藏文件的内容把之前改动的,未保存的内容还原回来

当然,硬盘可能也会出故障,因此,在实际工作中,最好还是把代码这些东西每天都上传到云端(Gitee/GitHub)



返回File对象下的所有文件名

在这里插入图片描述

如果File对象不是目录或者目录下没有文件,就会返回null,如下所示:

package io;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;

public class Demo1 {
    public static void main(String[] args) throws IOException {
        File file = new File("./test.txt");
        System.out.println(Arrays.toString(file.list()));
        System.out.println(Arrays.toString(file.listFiles()));
    }
}

在这里插入图片描述



看下基准路径下(博主的基准路径是 E:\JavaEE)的文件名,list()方法返回的是文件名,listFiles()方法是以File对象形式返回的文件名,如下所示:

package io;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;

public class Demo1 {
    public static void main(String[] args) throws IOException {
        File file = new File("./");
        System.out.println(Arrays.toString(file.list()));
        System.out.println(Arrays.toString(file.listFiles()));
    }
}

在这里插入图片描述

在这里插入图片描述



目录的创建

在这里插入图片描述

首先创建File对象,里面传入目录创建好后的位置,接着用mkdir进行创建即可,如下所示:

package io;

import java.io.File;
import java.io.IOException;

public class Demo1 {
    public static void main(String[] args) throws IOException {
        File file = new File("./test");
        file.mkdir();
    }
}

在这里插入图片描述


如果是创建多级目录,也就是目录套目录,那用mkdir就不行了(运行完后什么都创建不出来),就要使用mkdirs,如下所示

package io;

import java.io.File;
import java.io.IOException;

public class Demo1 {
    public static void main(String[] args) throws IOException {
        File file = new File("./test/aaa/bbb/ccc");
        file.mkdirs();
    }
}

在这里插入图片描述


文件重命名

在这里插入图片描述

就是创建两个对象,一个表示原来文件的位置,一个表示希望更改后这个文件的位置(包括名字),接着用renameTo进行更改
可以对一个文件进行重命名,如下所示(代码中加个Scanner,在用户输入后才会往下继续执行,方便观察效果)

package io;

import java.io.File;
import java.io.IOException;
import java.util.Scanner;

public class Demo2 {
    public static void main(String[] args) throws IOException {
        File file = new File("./test.txt");
        if(!file.exists()){
            file.createNewFile();
        }
        Scanner scanner = new Scanner(System.in);
        scanner.next();
        File file2 = new File("./test2.txt");
        file.renameTo(file2);

    }
}



用这个方法不仅可以实现文件的重命名,file2的路径也可以写成是其他地方的,这样就完成了文件剪切,在test目录中创建一个文本文件test2.txt,用renameTo实现一下文件的剪切,把这个文件再剪切进入JavaEE目录中,如下所示

package io;

import java.io.File;
import java.io.IOException;

public class Demo2 {
    public static void main(String[] args) throws IOException {
        File file = new File("./test/test2.txt");
        File file2 = new File("./test2.txt");
        file.renameTo(file2);
    }
}

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

3,文件内容操作

文件内容操作包括读文件(硬盘的数据读到内存中)和写文件(把内存的数据写到硬盘)
要使用流对象来进行文件内容操作(不是一次性把所有数据全加载 / 写出,而是像水流一样,一点点、连续地传输数据,所以叫流对象),各种编程语言,围绕文件的操作,都称为“流”

比如需要读取100个字节:

  1. 一次读取100个字节,直接读完
  2. 一次读取50个字节,分两次读完
  3. 一次读取25个字节,分四次读完
    …



Java中通过一系列的类,来表示流对象,主要分成了两个大类

  1. 字节流
    InputStream(读) OutputStream(写)
    读写数据的时候,以字节为基本单位,一次最少读取一个字节
    在读取二进制文件的时候,通常使用字节流

  1. 字符流
    Reader(读) Writer(写)
    读写数据时,以字符为基本单位,一次最少读取一个字符(一个字符可能对应多个字节,具体看编码方式)
    读写文本文件时,通常采用字符流

在IO过程中,输入和输出,是以CPU为基准,来进行考量的,如果方向是靠近CPU,就是输入(Input),如果方向是远离CPU,就是输出(Output)

在这里插入图片描述

1,字节流

创建文件输入流对象代码如下,传入要读取文件的位置(因为可能读取不到文件,所以要抛出个异常FileNotFoundException,它是IOException的子类)
InputStream是一个抽象类,因此不能直接用InputStream来创建实例,要用它的子类FileInputStream
创建文件流对象,这个过程,对应到操作系统中,就称为“打开文件”

public static void main(String[] args) throws FileNotFoundException {
        InputStream inputStream = new FileInputStream("./test.txt");
    }

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


读取调用inputStream的read方法,read方法里面如果不传入参数的话,就是一次读取一个字节
read方法读取字节,读取完成后以10进制的形式来返回,返回的也就是int类型,因此返回的最大值就是255(一个字节有8个比特位)
read()方法会从前往后读,当发现读取完了,读取不到了,就会返回-1
代码如下:

package io;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class Demo3 {
    public static void main(String[] args) throws IOException {
        InputStream inputStream = new FileInputStream("./test2.txt");
        while (true){
            int c = inputStream.read();
            if(c == -1){
                //读取完毕了
                break;
            }
            //转为16进制来看下
            System.out.printf("0x%x\n",c);
        }
    }
}

在test2.txt文本文档里写上一个hello,再运行程序,如下所示,铁汁们可以用在线utf8编码器看一下,看hello编码后的十六进制是不是这样的

在线utf8编码转换器
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述



read方法的无参版本就是一次读取一个字节,有参版本就是里面传入一个字节数组,字节数组的大小自己定义
读取时要用while循环,会尝试把这个字节数组给填满
传入字节数组后,read方法返回的int值就不是字节转化为十进制了,而是读取到的有效字节数,如果读取完毕,就会返回-1

字节数组初始创建时,每个元素都是0,如果文件比较大的话,会分多次读取,前几次读取都会把字节数组给塞满

package io;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class Demo3 {
    public static void main(String[] args) throws IOException {
        InputStream inputStream = new FileInputStream("./test2.txt");
        while (true){
            byte[] bytes = new byte[1024];
            int n = inputStream.read(bytes);
            if(n == -1){
                //读取完毕了
                break;
            }
            System.out.println("n = " + n);
            for(int i = 0;i < n;i++){
                System.out.printf("0x%x\n",bytes[i]);
            }
        }
    }
}

在这里插入图片描述



read方法还有一个三参数版本(如下图),那就是再传入一个off和len,尝试把参数中的字节数组填满,从off下标开始,最多填充len个(也就是一次只用数组的一部分)

在这里插入图片描述



使用IO流之后,要记得进行close(关闭资源),原因如下:
进程PCB中有一个属性,文件描述符表(顺序表),每次打开一个文件,都会在这个表里插入一个元素
文件描述符的长度是定长的,不能扩容,因此,光打开文件,不关闭文件,此时就会把表占满,后续再尝试打开文件,就会打开失败



写个readFile方法,里面包括文件的关闭,代码如下:
close方法要写在finally中,保证就算前面报错也能调用到
另外,如果没有读取到文件,inputStream为null,这时候就不需要关闭文件资源了(尝试用null调用close方法,就会报错),因此在finally中还要写if再去判断一下,代码如下所示:

package io;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class Demo5 {
    private static void readFile(){
        InputStream inputStream = null;
        try {
            inputStream = new FileInputStream("./test.txt");
            while (true){
                byte[] bytes = new byte[1024];
                int n = inputStream.read(bytes);
                if(n == -1){
                    break;
                }
                for(int i = 0;i < n;i++){
                    System.out.printf("0x%x\n",bytes[i]);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if(inputStream != null){
                    inputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        readFile();
    }
}



但是上面的写法铁汁们可能也感觉到了,有一种代码很繁杂的感觉,不美观
其实有一种更短,更美观的写法:
使用 try-with-resources,这样能保证在try块结束后,自动调用每个资源的close方法,如果资源变量为null,那就会自动忽略,代码如下所示:

package io;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class Demo5 {
    private static void readFile(){
        try (InputStream inputStream = new FileInputStream("./test2.txt")){
            while (true){
                byte[] bytes = new byte[1024];
                int n = inputStream.read(bytes);
                if(n == -1){
                    break;
                }
                for(int i = 0;i < n;i++){
                    System.out.printf("0x%x\n",bytes[i]);
                }
            }
        }catch (IOException e){
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        readFile();
    }
}

字节输出流,就是往文件里面写内容,write方法有三个参数(如下图),一个是以十进制的形式来写单个字节,一个是以数组的形式,最后一个是只用数组的一部分,跟inputStream的类似

在这里插入图片描述

可以一个一个字节来写,往文件中写一个abcd,这里可以在write方法中传入十进制,十六进制,八进制,二进制,都会当作int类型来处理,在write方法中传入hello每个字符的十六进制,就能将hello写到.txt文件中,如下所示:

在这里插入图片描述

package io;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class Demo6 {
    public static void main(String[] args) {
        try(OutputStream outputStream = new FileOutputStream("./test.txt")) {
            outputStream.write(0x61);
            outputStream.write(0x62);
            outputStream.write(0x63);
            outputStream.write(0x64);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

在这里插入图片描述



接下来试下给write方法传入数组,在文件中写入一个“你好”

在这里插入图片描述

需要注意:byte数组中每个元素是一个字节,但是JVM处理十六进制是当成int类型来处理的,int类型是4个字节,大转小,就需要进行一下强制类型转换

package io;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class Demo6 {
    public static void main(String[] args) {
        try(OutputStream outputStream = new FileOutputStream("./test.txt")) {
            byte[] bytes = {(byte) 0xe4,(byte)0xbd,(byte)0xa0,(byte)0xe5,(byte)0xa5,(byte)0xbd};
            outputStream.write(bytes);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

在这里插入图片描述



这里我们会发现一个问题,那就是这次新写进去的数据,把原来的aaaa数据给覆盖掉了
其实严格来说不是新的数据把老数据给覆盖掉了,创建新的输出流对象,就会清空文件内容(铁汁们可以试下在main方法中单独运行这段代码,文件内容就会被清空)

OutputStream outputStream = new FileOutputStream("./test.txt")

要让新写入的数据写到原来的数据的后面,而不是覆盖掉呢,就需要创建输出流时,传入一个true参数,如下所示:

package io;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class Demo6 {
    public static void main(String[] args) {
        try(OutputStream outputStream = new FileOutputStream("./test.txt",true)) {
            byte[] bytes = {(byte) 0xe4,(byte)0xbd,(byte)0xa0,(byte)0xe5,(byte)0xa5,(byte)0xbd};
            outputStream.write(bytes);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

在这里插入图片描述

2,字符流

前面的字节流可以读取任意类型的文件,因为文件在硬盘上的存储本质上就是字节,不分文件类型,字符流则是一次读取一个字符,适用于文本文件

字节输入流的抽象类Reader,实现要用FileReader,使用跟字节流比较类似,read方法的无参版本一次读取一个字符,读取到的是字符的Unicode 值,读取完成就返回-1

这里test.txt文件中有个hello,用字符输入流读取,再以十六进制的形式来打印

import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;

public class Demo01 {
    public static void main(String[] args) {
        try (Reader reader = new FileReader("D:\\Test\\test.txt")){
            while(true){
                int c = reader.read();
                if(c == -1){
                    break;
                }
                System.out.printf("0x%x\n",c);
            }
        }catch (IOException e) {
            e.printStackTrace();
        }
    }
}



字符流因为每次读取的是字符,所以如果read方法中传入数组的话,数组的类型是char[ ],read方法数组参数的返回值是读取到的字符个数

import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;

public class Demo01 {
    public static void main(String[] args) {
        try (Reader reader = new FileReader("D:\\Test\\test.txt")){
            while (true){
                char[] chars = new char[1024];
                int n = reader.read(chars);
                if(n == -1){
                    break;
                }
                System.out.println("n = " + n);
                for(int i = 0;i < n;i++){
                    System.out.println(chars[i]);
                }
            }
        }catch (IOException e) {
            e.printStackTrace();
        }
    }
}



字符输出流使用的是FileWriter,write中可以传入字符的Unicode码值,一次写入一个字符;也可以传入char数组,一次写入多个字符;还可以传入字符串,一次写入一个字符串(也可以传入三个参数,截取字符串或者字符数组的一部分写入)

在这里插入图片描述

之前的test.txt文件中写了个hello,这次就用传入字符数组往里面写入“字节跳动”,用传入字符串往里面写入"offer",创建输出流对象的时候传入个true,每次创建时不会清空文件,如下所示:

import java.io.*;

public class Demo01 {
    public static void main(String[] args) {
        try (Writer writer = new FileWriter("D:\\Test\\test.txt",true)){
            char[] chars = {'字','节','跳','动'};
            writer.write(chars);
            writer.write("offer");
        }catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在这里插入图片描述

3,缓冲流

?字节流和字符流会调用多次read和write方法,频繁的再磁盘(磁盘IO)读取或者写入数据,频繁触发磁盘IO,速度很慢

为了解决这个问题,Java中就加入缓冲流,降低了访问磁盘的次数,提升读写速度

  1. 读取文件数据时,缓冲流一次性从磁盘读取一大块数据,存入内存缓冲区,调用read读取时,直接读取内存缓冲区中的数据(速度非常快),缓冲区中的数据读取完了才访问磁盘,再次读取出一大块数据
  2. 往文件中写入数据时,先把数据写到内存缓冲区上,等到缓冲区满了或者数据传完了,关闭输出流资源了,再把缓冲区中的数据写入到磁盘中(也可以用flush方法,把当前缓冲区中的内容写到磁盘中)



缓冲流属于包装流,用缓冲流包含原始的流,字节流的缓冲流为BufferedInputStream和BufferedOutputStream,字符流的缓冲流为BufferedReader和BufferedWriter
缓冲流使用非常简单,创建缓冲流对象,包裹下原来的流对象即可(后续调用read或者write方法直接用缓冲流对象),就比如用字节流写入数组,代码如下:

import java.io.*;

public class Demo01 {
    public static void main(String[] args) {
        try (BufferedWriter bufferedWriter = new BufferedWriter( new FileWriter("D:\\Test\\test.txt",true))){
            char[] chars = {'字','节','跳','动'};
            bufferedWriter.write(chars);
            bufferedWriter.write("offer");
        }catch (IOException e) {
            e.printStackTrace();
        }
    }
}

释放资源时,只需要关闭缓冲流资源,内部包装的流也会自动关闭,上面代码中,只需要bufferedWriter.close即可(这里我们用的时try - with - resource写法,能自动关闭资源,这点了解下即可)



用缓冲输出流(BufferedWriter/BufferedOutputStream)往文件中写入数据时,当内存缓冲区满了或者调用close方法关闭资源了,就会把内存缓冲区中的内容写到磁盘中,但是这样数据写入是具有延后性的
在实际开发的一些场景中不想延后时间太长,就可以过一段时间调用下flush方法,强制将内存缓冲区的内容写入到磁盘中

可以在代码中加个读取输入代码,如果加了flush方法,执行到读取输入时,"字节跳动"就已经写到文件中了,不加flush方法的话,执行到这里,"字节跳动"就没有写到文件中

import java.io.*;
import java.util.Scanner;

public class Demo01 {
    public static void main(String[] args) {
        try (BufferedWriter bufferedWriter = new BufferedWriter( new FileWriter("D:\\Test\\test.txt",true))){
            char[] chars = {'字','节','跳','动'};
            bufferedWriter.write(chars);
            bufferedWriter.flush();
            Scanner scanner = new Scanner(System.in);
            int input = scanner.nextInt();
            bufferedWriter.write("offer");
        }catch (IOException e) {
            e.printStackTrace();
        }
    }
}

绝大多数读写文件场景下,都推荐使用缓冲流,缓冲流可以提高文件的读写效率🐵

4,文件搜索

代码要求:让用户输入文件名以及要搜索的目录,在目录中搜索该文件,如果查到就返回该文件的路径,并让用户选择是否要删除该文件(目录中是如果有多个名字相同的文件,将它们的路径一 一呈现给用户,让用户判断是否删除)

代码逻辑:

  1. 以字符串的形式读取用户输入的目录dir,以及要查询的文件名fileName,创建目录的File对象rootFile,判断rootFile是否为null,如果为null,说明该目录不存在,就退出查询
  2. 如果目录存在,就调用scanDir方法,传入rootFile和fileName,开始搜索目录,首先调用File的ListFiles方法,用File数组来接收返回值
  3. 接着遍历File数组,数组中的元素可能是文件,也可能是子目录,就递归调用scanDir方法搜索子目录中有没有符合要求的文件;如果数组中的元素是文件,就用contains方法比较文件名中是否包含fileName(如果选用equals方法,那用户就必须输入文件后缀名才能匹配上,就不太方便)
  4. 如果contains方法匹配上了,就调用tryDelete方法,传入要删除文件的File对象,打印出该文件的绝对路径,让用户判断是否要删除
import java.io.File;
import java.util.Scanner;

public class Test {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入要搜索的目录");
        String dir = scanner.next();
        System.out.println("请输入要查询的文件名");
        String fileName = scanner.next();

        File rootFile = new File(dir);
        if(!rootFile.isDirectory()){
            System.out.println("该目录不存在");
            return;
        }
        scanDir(rootFile,fileName);
    }

    public static void scanDir(File rootFile,String fileName){
        File[] files = rootFile.listFiles();
        if(files == null){
            return;
        }
        for(File file:files){
            if(file.isDirectory()){
                scanDir(file,fileName);
            }else if(file.isFile()){
                if(file.getName().contains(fileName)){
                    tryDelete(file);
                }
            }
        }
    }

    public static void tryDelete(File file){
        System.out.println("准备删除文件:" + file.getAbsolutePath());
        Scanner scanner = new Scanner(System.in);
        System.out.println("是否确认删除?(Y/N)");
        String choice = scanner.next();
        if(choice.equals("Y") || choice.equals("y")){
            file.delete();
            System.out.println("删除成功!");
        }
    }
}



接下来测试下,博主在D盘中创建了一个Test目录,Test目录中又放了个Test1目录和Test2目录,Test1目录和Test2目录中都创建了个hello.txt文件,就来测试下能否查找出并删除,如下所示:

在这里插入图片描述

5,普通文件的复制

要求:让用户输入要复制文件(源文件)的路径和复制文件(目标文件)的路径(复制后复制文件叫什么名字,放在哪里)

代码逻辑:

  1. 以字符串的形式读取用户输入的源文件路径和目标文件的路径,创建源文件的File对象,判断下该对象是不是文件类型,如果不是的话,就提醒用户源文件不存在,并return
  2. 如果源文件对象是文件类型的话,继续判断目标文件路径是否合法,通过getParentFile拿到源文件的父目录对象,接着判断父目录对象是不是目录类型,如果不是,就提示目标文件的父目录不存在,并且return(从Java体系中来看,所有的文件都是储存在目录中的,哪怕文件直接储存在D盘下,调用getParentFile拿到的也是D盘的根目录D:\)
  3. 前两步校验都通过后,就调用copy方法,传入源文件对象和目标文件对象两个参数,在copy方法中用try-with-resources的方式来写代码,try的()中是可以输入流和输出流对象都创建的,后面销毁也是两个都销毁
  4. write方法中传入三个参数版本的,如果写一个参数版本的,直接传入数组,可能最后一次只读取到了200个字节,但是却写入了1024个字节的数据,就会有很多多余的字节
import java.io.*;
import java.util.Scanner;

public class Test {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入源文件的路径:");
        String srcPath = scanner.next();
        System.out.println("请输入目标文件的路径:");
        String destPath = scanner.next();

        File srcFile = new File(srcPath);
        if(!srcFile.isFile()){
            System.out.println("源文件不存在");
            return;
        }

        File destFile = new File(destPath);
        File parentFile = destFile.getParentFile();
        if(!parentFile.isDirectory()){
            System.out.println("目标文件的父目录不存在");
            return;
        }
        copy(srcFile,destFile);
    }

    public static void copy(File srcFile,File destFile){
        try(InputStream inputStream = new FileInputStream(srcFile);
            OutputStream outputStream = new FileOutputStream(destFile)) {
            while (true){
                byte[] buffer = new byte[1024];
                int len = inputStream.read(buffer);
                if(len == -1){
                    break;
                }
                outputStream.write(buffer,0,len);
            }
            }  catch (IOException e) {
            e.printStackTrace();
        }

    }
}



接下来测试下代码,在D盘中搞个Test目录,目录里放一张老黄的照片,目标文件的路径还是Test目录,只是文件名改一下,如下所示:

在这里插入图片描述

在这里插入图片描述

结语💕💕

  • 文件 IO 在编程里很常用,例如日志、配置、静态文件都是通过文件IO来读取的,如果数据不需要复杂查询、多条件筛选、事务这些功能,就可以不存到数据库中,通过文件IO存到文件中,通常开销会更低
  • 大部分单机游戏的存档,都是通过文件IO存储在文件中的,例如黑猴,boss打过后想要重新打比较麻烦,有些大佬就找到存档文件的位置,修改下,就可以重新打了🐵

以上就是今天的所有内容啦~完结撒花~🥳🎉🎉

在这里插入图片描述

Android音频学习(十四)——加载音频设备 loadHwModule 是 Android 音频系统的核心初始化函数,负责加载音频硬件抽象层(HAL)的模块实现。它建立 AudioPolicyService 与底层硬件的桥梁,将配置文件(audio_policy_config.xml)中的标签<module>定义转化为可操作的硬件对象,加载的是音频硬件模块(HAL实现),每个模块对应一种音频设备类型,以动态库的形式存在,负责与底层音频硬件交互。 阅读详情

相关推荐

SVG绘制圆环进度条

在我们的大屏可视化项目中,经常会用到各种各样的图表。与传统的表格展示、枯燥的文字阐述相比,图表展示则使用户看起来更加直观、数据的展示则更加一目了然。本文基于svg绘图技术结合前端技术栈vue,以工作中常用的环形进度条为例,简单阐述一下绘制进度条的一些思路。............

qq_40289557的博客 8358

【JavaEE】——文件IO(万字长文)

文件路径,文本文件,二进制文件,File类,文件流,字节流(InputStream,OutputStream)字符流(Reader,Writer)

阿华的博客 1526

CDR学习笔记——02

这篇写一些高级CDR的架构原理。

... 1014

文件操作与IO(3) 文件内容的读写——数据流

在进程中,PCB里面有文件描述符表,记录了当前进程都打开了哪些文件,这个文件描述符表是由数组 / 顺序表组成的,数组里面的每一个元素都代表着是一个结构体,里面包含了文件的一些属性,每打开一个文件,在文件描述符表就会被多占一个位置,而文件描述符表的资源是有限的,如果不关闭,当它被耗尽了,后续再打开文件就会失败,从而引发其他的逻辑出问题;数据流的特点:类似水流,假设要读写100字节的数据,可以每次读写10字节的数据,分10次读写完,也可以每次读写5字节,分20次读写完,或者一次性读写完100字节的数据。

cool_tao6的博客 1444

Kolla 容器化 高可用OpenStack 部署与 Ceph 集群集成

本文介绍了 Kolla 项目在容器化 OpenStack 部署和管理方面的应用,以及与 Ceph 集群的集成。Kolla 项目通过容器技术提供了一种简化和自动化的 OpenStack 部署方法,同时实现了易于升级和回滚的特点。本文还探讨了 Kolla 在实现零宕机升级方面的进展,并分析了其对 OpenStack 用户和社区的重要意义。

we22635的博客 2701

大模型-高通qnn基础

提供较低级别、高度可定制的统一API,通过单独的库加速所有AI加速器核心上的AI模型, 可以直接用于针对特定的加速器核心或从流行的运行时(包括Qualcomm Neural Processing SDK、TensorFlow Lite和ONNX运行时)委派工作负载。一个支持异构计算、系统级配置的一体化SDK,旨在将AI工作负载引导到我们平台上的所有加速器核心。为开发人员提供灵活性,包括核心间协作支持和其他高级功能。是一个为训练好的神经网络模型提供高级量化和压缩技术的库。

点滴的岁月 4082

【JavaEE初阶】深入透析文件-IO关于文件内容的操作(四种文件流)

本期主要讲解了关于文件内容操作中,比较重的文件流的操作,包括:inputstream,outputstream,writer,reader,以及重要的小知识点穿插在其中~~

GGBond778的博客 2082

Trae编程工具Cline插件深度集成与Claude 3.7 API Key高级配置实战

本文详细介绍了如何在Trae编程工具中深度集成Cline插件并配置Claude 3.7 API Key的高级技巧。通过实战案例,展示了如何提升代码补全质量、实现多轮对话记忆及自定义代理设置,特别适合全栈工程师和需要私有化AI服务的团队。文章还涵盖了安装流程、API Key获取方式及企业级部署的最佳实践。

weixin_28829903的博客 435

JavaEE进阶-文件操作与IO流核心指南

本文是Java文件操作和IO流的学习笔记,主要包含两大核心内容:`java.io.File`类和IO流的使用。 File类于管理文件属性(路径、大小等),但不负责读写文件内容。文章详细介绍了文件路径、创建删除、目录操作、重命名移动等常用方法。

weixin_73966418的博客 1351

论文阅读: SIGIR 2025 ID-Free Not Risk-Free: LLM-Powered Agents Unveil Risks in ID-Free Recommender Syste

咱们平时用的推荐系统(比如购物APP推商品、视频APP推剧),大多是“有ID”的——每个用户、每个商品都有个专属ID,系统靠这些ID记录你的浏览、购买历史,再给你推喜欢的东西。但这种方式有个大问题:新用户、新商品刚上线时没有ID历史数据,系统没法精准推荐,这就是“冷启动”难题。后来人们搞出了“无ID推荐系统”:不用ID了,改成直接分析商品的文字信息(比如商品标题、描述),靠大语言模型(LLM,类似ChatGPT的技术)把文字转成“语义代码”,再通过这些“代码”判断你可能喜欢什么。

CSPhD-winston的博客 975

arcgis计算栅格平均值

打开FC栅格数据和非水体矢量数据 利用矢量数据提取对应栅格的非水体部分 2.1打开空间分析工具à提取分析à按掩膜提取 输入对应栅格数据和矢量数据 2.2提取结果如下 进行计算FC平均值 3.1打开空间分析工具à多元分析à波段集统计 输入对应栅格和输出路径 3.2统计结果如下 ...

Z_W_H_的博客 5370

文件 IO

本文系统介绍了Java文件操作相关内容,包括文件分类、路径表示、文件系统操作和内容读写。主要内容有:1.文件按格式分为文本文件和二进制文件,按路径分绝对路径和相对路径;2.使用File类进行创建、删除、重命名等文件系统操作;3.通过字节流(InputStream/OutputStream)和字符流(Reader/Writer)实现文件内容读写;4.介绍了try-with-resource语法避免资源泄露;5.提供了文件搜索、复制和内容查找三个典型应用示例。文章全面讲解了Java文件操作的基础知识和实用技巧。

weixin_41965831的博客 893

Claude Code 100个真实案例 - 用AI搭建LangChain多工具Agent(自主搜索+查询)

本案例展示如何使用 Claude Code 搭建一个 LangChain 多工具 Agent 系统。Agent 能够自主决定调用搜索引擎、数据库查询、天气查询、计算器等工具,像人类助手一样拆解问题并逐步解决。

yueyeguzhuo的专栏 557

Javaee文件的io操作

创建文件,删除文件,创建目录,重命名文件。

2302_80113478的博客 946

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

文件系统与IO操作:深入解析与Java实践

本文系统探讨了文件系统的理论基础与Java文件操作API。首先阐述了文件系统核心概念,包括文件抽象、目录树结构、路径解析机制和权限模型。随后详细解析了Java IO流体系,涵盖字节流/字符流区别、缓冲区优化策略及文本文件编码处理。在高级实践部分,介绍了目录遍历算法、文件搜索工具实现和大文件处理技术。最后对比了传统IO与现代NIO.2 API,并提供了性能优化方案和资源管理最佳实践。全文通过理论结合代码示例,完整呈现了文件操作的各个关键环节。

2301_79949064的博客 896

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Java文件字符流和字节流中的实战

针对文本文件,Java提供了一组类——”字符流“,代表类(Reader,Writer)。同样的,Java也为二进制文件提供了一组操作类——”字节流“,代表类(InputStream,OutputStream)。其实这两种的对文件操作原理是相同的,只是针对的文件不同,所以才有了字符流和字节流之分。因为有了字节流与字符流之分,所以相对应的,字节流最低读写字符是”一个字节“,字符流也有对应限制,字符流最低读写”一个字符 “。3.在判定的查询的词中,是否存在上述内容。,不同的文件,操作方法也不尽相同。

闲来垂钓碧溪上的博客 553

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

Java文件IO

Java文件IO, 文件的存储方式 文件的路径,相对路径,绝对路径, 文件检索, 文件的种类, 文本文件,二进制文件, 字节流读写数据, 字符流读写数据, 文件搜索功能, 文件复制功能, 文件内容搜索功能

Coding经历 1603

Day16_IO框架1(File类, IO流, 字节流字符流, IO异常, Properties)

文章目录一. File类1.1 概述1.2 File类的静态成员变量1.3 路径绝对路径相对路径1.4 构造方法1.5 常用方法获取功能的方法判断功能的方法创建删除功能的方法遍历目录的方法【例】打印多级目录 (递归)【例】文件搜索1.6 FileFilter接口【例】文件搜索(FileFilter优化)【例】补充:文件搜索(Lambda优化)二. IO流的概念2.1 什么是IO?2.2 什么是流?2.3 流的分类输入流 和 输出流字节流 和 字符流节点流 和 处理流三. 字节流3.1 字节流的父类:3.2

不愿透露姓名的马建国的博客 1258

Java文件IO操作知识点

I:input输入 O:output输出,这是一套人为规定的规则,下面这个图方便我们理解输入输出的定义,统一以CPU为基准在操作系统中其实把很多的资源都抽象成文件,我们在这里所说的文件就是"狭义"文件,平时保存在硬盘上的文件,文件夹也是一种文件,我们称之为目录文件,在硬盘上存储着很多文件和目录,目录之间又存在这一套嵌套关系,这整个结构是一个树形结构N叉树,

2301_79288225的博客 650

文件操作和 IO(二):文件内容操作 => 流对象

InputStream, FileInputStream, OutputStream, FileInputStream, Reader, FileReader, Writer, FileWriter => 文件内容操作(读/写)

2401_83595513的博客 1296

【Java EE】文件IO

文件IO

weixin_75071792的博客 1012

JavaEE初阶-文件IO2

介绍了使用字符流、字节流读写文件的方法,一些细节知识点以及最终总结作用的三道文件IO的例题。

qq_45965652的博客 1574

[JavaSE] 文件操作和IO

文件包括狭义的文件和广义的文件,狭义的文件就是硬盘上存储的文件,广义上的文件就是操作系统进行资源管理的一种方式,将很多的硬件和软件资源抽象成“文件”来进行表示。下面就是狭义上的文件:第一个我们在生活中叫做文件夹,但是在计算机领域专业术语叫做目录,第二个就是文件,这些都是保存在硬盘上的。计算机中能够存储数据的有:硬盘,内存,CPU。硬盘又分为机械硬盘和固态硬盘,机械硬盘的读写速度大概为:1秒几百MB,固态硬盘读写速度大概为:1秒几个GB,但是机械硬盘比固态硬盘便宜。

2402_83046353的博客 691

【文件操作】IO

1.狭义的文件指的是硬盘上的文件和目录(文件夹)。2.广义的文件泛指计算机中很多的软硬件资源。操作系统中把很多的硬件设备和软件资源抽象成了文件,按照文件的方式来统一管理。3.文件的类型存的是文本、字符串存的是二进制数据,不一定是字符串了4.路径以C: 、D:盘符开头的路径以当前所在的目录(工作目录)为基准,以 . 或 .. 开头找到指定路径。

w2022009105的博客 196

Java文件IO相关类的使用与案例

本篇文章将介绍文件IO,文件IO即文件输入(Input)与输出(Output),文件输入就是将文件中的内容读入内存中,文件输出就是将程序输出的内容写入到文件中,说了文件的输入与输入的概念,那你知道什么是文件吗?

未见花闻的博客 857
上一篇: Java线程(八)JUC包中常用类的解析
下一篇: 初识网络通信,网络发展背景,TCP/IP五层模型简介
洋不写bug
博客等级 码龄2年 87粉丝 102原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值