javaee-文件操作/io

①文件

(1)文件:一串长期保存在磁盘上的字节序列

(2)树型结构组织和⽬录:目录(文件夹)是操作系统用「树形结构」组织文件的核心载体

(3)⽂件路径:操作系统定位文件 / 文件夹的 "地址"

(4)其他:即使是普通⽂件,根据其保存数据的不同,也经常被分为不同的类型,我们⼀般简单的划分为⽂本⽂件和⼆进制⽂件,分别指代保存被字符集编码的⽂本和按照标准格式保存的⾮被字符集编码过的⽂件

②java中操作文件

主要使用 java.io.File 这个类对文件进行操作

(1)构造方法:

注意要么用/要么用\\

./开头指的是在这个代码源文件当前的所处目录(创建文件)

java 复制代码
// 绝对路径(Windows,注意\需要转义为\\)
File absoluteFile = new File("C:/Users/test/a.txt");
// 相对路径(相对于程序运行的当前目录)
File relativeFile = new File("./test/b.txt");
// 目录路径(文件夹)
File dirFile = new File("C:/Users/test/docs");

(2)常用方法

表格

修饰符及返回值类型 方法签名 说明
String getParent() 返回 File 对象的父目录文件路径
String getName() 返回 File 对象的纯文件名称
String getPath() 返回 File 对象的文件路径(构造时传入的原路径)
String getAbsolutePath() 返回 File 对象的绝对路径(基于当前工作目录拼接,保留相对符号)
String getCanonicalPath() 返回 File 对象的修饰过的绝对路径(解析 ./..、符号链接,返回标准化路径,需抛出 IOException
boolean exists() 判断 File 对象描述的文件 / 目录是否真实存在
boolean isDirectory() 判断 File 对象代表的是否是一个目录(文件夹)
boolean isFile() 判断 File 对象代表的是否是一个普通文件
boolean createNewFile() 根据 File 对象,自动创建一个空文件。成功创建后返回 true,文件已存在则返回 false
boolean delete() 根据 File 对象,删除该文件 / 空目录。成功删除后返回 true,目录非空则删除失败
void deleteOnExit() 根据 File 对象,标注文件将被删除,删除动作会到 JVM 运行结束时才会执行
String[] list() 返回 File 对象代表的目录下的所有文件名(仅名称,无路径)
File[] listFiles() 返回 File 对象代表的目录下的所有文件 / 子目录,以 File 对象表示
boolean mkdir() 创建 File 对象代表的目录(仅创建单层,父目录不存在则失败)
boolean mkdirs() 创建 File 对象代表的目录,若父目录不存在则自动创建中间目录(推荐用于多级目录)
boolean renameTo(File dest) 进行文件 / 目录改名,也可视为剪切、粘贴操作(跨文件系统可能失败)
boolean canRead() 判断用户是否对文件有可读权限
boolean canWrite() 判断用户是否对文件有可写权限

Java File 类方法使用示例总览

java 复制代码
import java.io.File;
import java.io.IOException;

public class FileDemo {
    public static void main(String[] args) throws IOException {
        // 1. 创建 File 对象(可以是不存在的路径)
        // 这里用相对路径:当前项目下的 test 文件夹里的 a.txt
        File file = new File("test/a.txt");

        // 2. 获取路径相关方法
        System.out.println("===== 路径方法 =====");
        System.out.println("getParent():父目录路径 = " + file.getParent());
        System.out.println("getName():文件名称 = " + file.getName());
        System.out.println("getPath():构造时的原路径 = " + file.getPath());
        System.out.println("getAbsolutePath():绝对路径 = " + file.getAbsolutePath());
        System.out.println("getCanonicalPath():标准化绝对路径 = " + file.getCanonicalPath());

        // 3. 判断文件/目录是否存在、类型
        System.out.println("\n===== 判断方法 =====");
        System.out.println("exists():是否存在 = " + file.exists());
        System.out.println("isDirectory():是否是目录 = " + file.isDirectory());
        System.out.println("isFile():是否是普通文件 = " + file.isFile());

        // 4. 创建文件
        System.out.println("\n===== 创建文件 =====");
        // 先创建父目录 test
        new File("test").mkdirs();
        boolean createSuccess = file.createNewFile();
        System.out.println("createNewFile():创建成功? = " + createSuccess);

        // 5. 权限判断
        System.out.println("\n===== 权限方法 =====");
        System.out.println("canRead():可读 = " + file.canRead());
        System.out.println("canWrite():可写 = " + file.canWrite());

        // 6. 遍历目录(查看 test 目录下的文件)
        System.out.println("\n===== 遍历目录 =====");
        File dir = new File("test");
        String[] names = dir.list();
        System.out.println("list():目录下文件名:");
        for (String name : names) {
            System.out.println("- " + name);
        }

        File[] files = dir.listFiles();
        System.out.println("listFiles():目录下 File 对象:");
        for (File f : files) {
            System.out.println("- " + f.getPath());
        }

        // 7. 重命名(剪切/移动效果)
        System.out.println("\n===== 重命名/移动 =====");
        File newFile = new File("test/b.txt");
        boolean renameSuccess = file.renameTo(newFile);
        System.out.println("renameTo():重命名成功? = " + renameSuccess);

        // 8. 删除文件
        System.out.println("\n===== 删除文件 =====");
        boolean deleteSuccess = newFile.delete();
        System.out.println("delete():删除成功? = " + deleteSuccess);

        // 9. 删除目录(必须为空)
        System.out.println("\n===== 删除空目录 =====");
        boolean deleteDir = dir.delete();
        System.out.println("delete():删除空目录成功? = " + deleteDir);

        // 10. JVM 退出时删除(临时文件常用)
        File tempFile = new File("temp.txt");
        tempFile.createNewFile();
        tempFile.deleteOnExit();
        System.out.println("\ndeleteOnExit():JVM 结束后会自动删除 temp.txt");
    }
}

(1)创建文件

创建文件要用" "包围

./就是在当前文件夹,不加./也是当前文件夹,

java 复制代码
File file1=new File("./test1.txt");
        File file2=new File("test2.txt");
        file1.createNewFile();
        file2.createNewFile();

如果只写FIle的实例化,不写createNewFile,那么只造 "路径对象",不造真实文件,真是文件夹里不会有这个文件!

但是只写FIle的实例化,没有createNewFile,依旧可以进行路径查询,创建文件 / 文件夹,判断文件状态是否存在 (是存在的) ,也能删除 等等

(2)查询文件

java 复制代码
// 1. 创建文件路径对象(代表当前目录下的 test1.txt,只是路径,不创建真实文件)
        File file1=new File("./test1.txt");
        // 2. 判断文件/目录是否真实存在 → 不存在,输出 false
        System.out.println(file1.exists());
        // 3. 判断是否是文件夹 → 不存在,输出 false
        System.out.println(file1.isDirectory());
        // 4. 判断是否是普通文件 → 不存在,输出 false
        System.out.println(file1.isFile());
        // 5. 在硬盘上**真正创建空文件 test1.txt**
        file1.createNewFile();
        // 6. 现在文件已创建,存在 → 输出 true
        System.out.println(file1.exists());
        // 7. 这是文件,不是文件夹 → 输出 false
        System.out.println(file1.isDirectory());
        // 8. 这是普通文件 → 输出 true
        System.out.println(file1.isFile());
        // 9. 再次尝试创建文件(文件已存在,创建失败) → 输出 false
        System.out.println(file1.createNewFile());

(3)删除文件

java 复制代码
  // 1. 创建一个路径对象:代表当前目录下的 test1.txt(只是地址,不创建文件)
        File file1=new File("./test1.txt");
        // 2. 根据路径,在硬盘上【真正创建空文件 test1.txt】
        file1.createNewFile();
        // 3. 判断文件是否存在 → 刚创建完,存在 → 输出 true
        System.out.println(file1.exists());
        // 4. 根据路径,【真正删除硬盘上的 test1.txt 文件】
        file1.delete();
        // 5. 再次判断文件是否存在 → 已经删掉了,不存在 → 输出 false
        System.out.println(file1.exists());
java 复制代码
File file1=new File("./test1.txt");
        file1.createNewFile();
        System.out.println(file1.exists());//true
        file1.deleteOnExit();//等程序运行结束、JVM 关掉时,再自动删除文件
        System.out.println(file1.exists());//true

(4)目录的创建

java 复制代码
File dir = new File("aba");
        dir.mkdir();//只能建一层(在当前源文件同目录下创建)
java 复制代码
File dir = new File("a/b/c");
        dir.mkdirs();//可以创建多层

(5)文件重命名

java 复制代码
File file1=new File("./abc.txt");
        file1.createNewFile();//必须写这个或者保证abc.txt存在,不然无法改名
        File file2=new File("./xzx");
        boolean res=file1.renameTo(file2);//这个也会返回一个boolean值,用来表示是否修改成功
        System.out.println(res);

③⽂件内容的读写⸺数据流

计算机中对文件的操作是通过"流对象"实现的

前置知识:

try(...):Java 自动关闭流的写法,执行完会自动释放资源

true开启追加模式 → 新内容写在文件末尾,不覆盖原有内容

字符流想用数组输入用char数组 字节流就用byte数组

(1)字节流: 以 "字节" 为单位读写文件的流,针对二进制,但是英文也能用,能读所有文件(图片、视频、文本、exe...)

输入:InputStream (文件内容提取到编程软件)

输出:OutputStream (代码内容写进文件)

字节流输出(其实是把代码里的东西写进文件):

实例化后用 实例化名.write的方法

注意要用File+方法名 的那个方法(FileOutputStream),后面都是

java 复制代码
 try (OutputStream outputStream = new FileOutputStream("./output.txt")) {//覆盖
            outputStream.write(97);
            outputStream.write(98);
            outputStream.write(99);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

附:数组输出版

如果在文件名后面加 true,那么会从覆盖变成添加

java 复制代码
try (OutputStream outputStream = new FileOutputStream("./output.txt",true)) {
            byte bytes[]={97,98,99,100};
            outputStream.write(bytes);//覆盖
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

字节流输入:

实例化括号传入路径文件,然后用 实例化名.read的方法

为什么用16进制输出?因为二进制文件根本不是文字,直接打印会乱码

为什么每次读一个,读到-1就停止循环?read() 方法的设计规则就是:

  • 能读到数据 → 返回 0 ~ 255(一个字节的范围)
  • 读不到数据(文件结束) → 返回 -1
java 复制代码
try(InputStream inputStream=new FileInputStream("C:/appverifUI.dll")){
            while(true){
                int b=inputStream.read();
                if(b==-1){
                    break;
                }
                System.out.printf("0x%x\n",b);
            }
        }catch (IOException e){
            throw new RuntimeException(e);
        }

(2)字符流:

Reader:输入

Writer:输出

跟字节流一样都是输出就是代码网文件里输 ;输入就是文件往编程软件里输

字符流输出:

java 复制代码
try(Writer writer=new FileWriter("./output.txt")){
    writer.write("helloworld");
}catch (IOException e){
    throw new RuntimeException(e);
}

升级版:

java 复制代码
try (Writer writer = new FileWriter("./output.txt", true);//开启添加不覆盖模式
             BufferedWriter bufferedWriter = new BufferedWriter(writer)) {
            bufferedWriter.write("Hello World");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

字符流输入(从文件中读取到软件里):

逐个字符读取版:

read一次只会读一个字符,如果没了就返回-1(先读字节,在转成字符!所以不会读到-1 字节范围0~255)

java 复制代码
try(Reader reader=new FileReader("./output.txt")){
             while(true){
                 int c=reader.read();
                 if(c==-1){
                     break;//读取完毕
                 }
                 System.out.print((char)c);
             }
        }catch (IOException e){
            throw new RuntimeException(e);
        }

批量读取版:

先创建char数组

int n接取的是读到了多少个字符!因为1024数组长度优先一次读不完!for循环是把先读到的输出,while循环是为了读下一组字符,跟上面while循环每次读一个字符的作用不一样

java 复制代码
try(Reader reader=new FileReader("./output.txt")){
            while(true){
                char buf[]=new char[1024];
                int n=reader.read(buf);
                if(n==-1){
                    break;//读取完毕
                }
                for(int i=0;i<n;i++){
                    System.out.print(buf[i]);
                }//这个输出不是必要的,这里其实算是模拟一个读取后输出的操作
            }
        }catch (IOException e){
            throw new RuntimeException(e);
        }

应用1:扫描指定⽬录,并找到名称中包含指定字符的所有普通⽂件(不包含⽬录),并且后续询问⽤⼾是否要删除该⽂件

主体部分:先用String接收输入的目录路径,然后用这个路径创建一个FIle(仅仅是创建一个 "操作对象 / 代表对象",而不是创建文件夹)

然后用api判断是不是目录,不是就直接结束

是目录就输入关键词,然后进扫描

java 复制代码
import java.io.File;
import java.util.Scanner;

public class demo12 {
    
    public static void main(String[] args) {
        Scanner cin=new Scanner(System.in);
        System.out.println("输入要搜索的目录");
        String rootDir=cin.next();
        File rootFile=new File(rootDir);//创建操作对象,而不是去创建文件夹
        if(!rootFile.isDirectory()){
            System.out.println("输入的不是目录");
            return;
        }
        else{
            System.out.println("请输入要关键字");
            String key=cin.next();
            scanDir(rootFile,key);
        }
    }
}

扫描方法先接收根目录和关键词

先用File数组接受所有文件/文件夹 (都可以接收)

然后如果数组为空那就没有目标对象了直接结束

如果有,那就用for循环遍历当前文件夹中每一个文件夹/文件

然后两个判断

如果是文件:那就去判断文件名是否包含关键词,如果有,那就让用户输入是否删除;没有就直接跳过

如果是文件夹:那就把这个文件夹当根目录喂给扫描方法执行递归

java 复制代码
    public static void scanDir(File rootFile,String key){
        File filesarr[]=rootFile.listFiles();//提取对象目录中有的文件/文件夹
        if(filesarr==null){//没有对应判空方法,手动判断
            return;
        }
        else{
            for(int i=0;i<filesarr.length;i++){//遍历每一个对象
                System.out.println("遍历"+filesarr[i].getAbsolutePath());
                if(filesarr[i].isFile()) {//如果是文件,那就进一步
                    if (filesarr[i].getName().contains(key)) {//如果是文件,名称还包含关键字,那就删除
                        System.out.println("发现目标删除文件" + filesarr[i].getAbsolutePath() + ",是否删除?(y/n)");
                        Scanner cin = new Scanner(System.in);
                        String in = cin.next();
                        if (in.equals("y")) {
                            filesarr[i].delete();
                            System.out.println("文件已删除");
                        }
                    }
                }
                else{//如果是
                    scanDir(filesarr[i],key);
                }
            }
        }
    }

应用2:进⾏普通⽂件的复制

先输入源文件路径,然后输入目标路径(这里虽然不用你手动先创建一个同后缀文件。但是你需要手写一个后缀相同的文件到这个文件夹里,名字自己定)

然后创建File去操控源文件,如果不是文件,那就关闭程序

然后创建FIle去操控目标文件位置,由于对象是文件,那就判断它的parent文件夹是不是文件夹(起判断这个文件夹是否存在的效果)

到了try中,我们选用字节流(因为什么类型后缀都适用)

创建InputStream和OutputStream对象,用;隔开即可创建两个

先用byte数组批量接受inputstream的read,到-1后break就用outputstream的write写进目标文件,位置从0-n

java 复制代码
import java.io.*;
import java.util.Scanner;

public class demo13 {

    public static void main(String[] args) {

        Scanner cin=new Scanner(System.in);
        System.out.println("输入源文件路径");
        String rootPath=cin.next();
        System.out.println("输入目标路径");
        String targetPath=cin.next();
        File rootFile=new File(rootPath);
        if(!rootFile.isFile()){
            System.out.println("输入的源文件不存在/不是文件");
            return;
        }
        File targetFile=new File(targetPath); //后面的FileOutputStream会自动创建文件
        if(!targetFile.getParentFile().isDirectory()){
            System.out.println("目标文件所在目录不存在");
            return;
        }

        try(InputStream inputStream=new FileInputStream(rootFile); OutputStream outputStream=new FileOutputStream(targetFile)){
            while(true){
                byte arr[]=new byte[1024];
                int n=inputStream.read(arr);
                if(n==-1){
                    break;
                }
                outputStream.write(arr,0,n);
            }
        }catch(IOException e){
            throw new RuntimeException(e);
        }
    }
}

疑问点:

①所以目标文件需要我先自己手动创建?:不需要,因为你输入目标文件的时候最后一个就是带后缀的文件,后面FileOutputStream会自动按照这个去创建文件

②为什么要用字节流不用字符流?电脑上所有文件底层都是字节,所以字节流万能

③为什么是outputStream.write(arr,0,n);?:这个是从从数组的第 0 个位置开始取数据,读取n个数据,不写的话会损坏! 字符流的writer.write("");也有这个用法

所以是从0-n,那么就可以用这个代替

java 复制代码
for (int i = 0; i < n; i++) {
    outputStream.write(arr[i]);
}

应用3:在指定⽬录下找到文件名称或者文件内容中包含指定字符的普通⽂件(不包含⽬录)

先看main部分:先输入搜索的文件夹路径(+判断),然后再输入关键词,随后直接传入扫描方法即可

java 复制代码
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.Scanner;
public class demo14 {


    public static void main(String[] args) {
        Scanner cin=new Scanner(System.in);
        System.out.println("输入搜索的路径");
        String rootPath=cin.next();
        File rootFile=new File(rootPath);
        if(!rootFile.isDirectory()){
            System.out.println("输入的不是文件夹");
            return;
        }
        System.out.println("输入关键词");
        String key=cin.next();
        scanDir(rootFile,key);
    }

扫描方法:

公式化文件数组+判空

不为空情况:循环遍历每一个文件/文件夹,如果是文件,那就传入查找方法

如果是文件夹,那就再传入扫描方法进行递归即可

java 复制代码
public static void scanDir(File rootFile,String key){
        File filearr[]=rootFile.listFiles();
        if(filearr==null){
            return;
        }
        for(int i=0;i<filearr.length;i++){
            if(filearr[i].isFile()){
                findFile(filearr[i],key);
            }
            else{
                scanDir(filearr[i],key);
            }
        }
    }

查找方法:

先判断文件名是否包含关键词,包含直接输出结束

不包含:先创建一个StringBuilder存储所有字符,然后用字符流输入:

字符流用的是char数组,老方法用n接收reader的read方法,同时括号内写char的数组名,到-1停止

然后每一次都存入StringBuilder里

只把数组里【有效、真实读到的字符】追加进去,不添加垃圾空字符!

  • chars:你读到内容的字符数组
  • 0 :从数组第 0 位开始拿
  • n真正读到的有效字符数量

所有存入后,用indexof (StrnigBuilder没有contains,当然也可以转为String后使用contains),如果结果>=0那就是找到了(找不到的时候返回-1)

java 复制代码
public static void findFile(File file,String key){//由于太多,所以专门分开写
        if(file.getName().contains(key)){
            System.out.println("找到目标文件"+file.getAbsolutePath());
        }
        else{
            StringBuilder stringBuilder=new StringBuilder();
            try(Reader reader=new FileReader(file)){
                while(true){
                    char chars[]=new char[1024];
                    int n=reader.read(chars);
                    if(n==-1){
                        break;
                    }
                    stringBuilder.append(chars,0,n);//防止最后一次读取输入一堆空字符,所以范围设置0-n
                };
            }catch (IOException e){
                throw new RuntimeException(e);
            }

            if(stringBuilder.indexOf(key)>=0){
                System.out.println("该文件包含关键词"+file.getAbsolutePath());
            }
        }
    }j
相关推荐
ic爱吃蓝莓2 小时前
每日一题·字母异位词分组
java·开发语言
spencer_tseng2 小时前
[Flex SpringMVC Hibernate] to [SpringCloud + Hibernate + H5]
java·spring cloud·hibernate
丶小鱼丶2 小时前
数据结构和算法之【堆】
java·数据结构
Cosmoshhhyyy2 小时前
《Effective Java》解读第45条:谨慎使用Stream
java·开发语言·c#
A Everyman3 小时前
Java 高效生成 Word 文档:poi-tl 的使用
java·pdf·word·poi-tl
短剑重铸之日3 小时前
深入理解Sentinel: 01 一次服务雪崩问题排查经历
java·sentinel·降级熔断
马猴烧酒.3 小时前
【面试八股|操作系统】操作系统常见面试题详解笔记
java·linux·服务器·网络·数据结构·算法·eclipse
薛定谔的悦3 小时前
《储能系统中的故障定位》
java·服务器·前端
六义义3 小时前
SpringBoot 超详细全解(入门 + 实战 + 原理 + 面试)
java·spring boot·面试