Java中的文件操作「基础知识」

通常说的文件时磁盘上存储的文件,但文件的概念更加广泛,为了操作系统方便管理硬件设备,把一切资源都抽象成文件进行管理「比如操作网卡,显卡,CPU,打印机等设备」

1. File类的使用

1.1 读取文件属性

package file;

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

public class Demo1 {
    public static void main(String[] args) throws IOException {
        // 绝对路径
        File f = new File(" /Users/cxf/java/4.System/src/file/content/test.txt");
        System.out.println(f.getParent());
        System.out.println(f.getName());
        System.out.println(f.getPath());
        System.out.println(f.getAbsolutePath());
        System.out.println(f.getCanonicalPath());
        System.out.println("**********");
        /*
        相对路径:一定要找对应的路径作为文件描述的基准
        Tomcat:如果打了个 war 包,在 Tomcat 中运行,部署在 webapps 里,基准路径就会是对应 Tomcat 工作的 bin 目录
        打了个 jar 包,通过 java -jar [jar包名],基准路径就是运行 java 命令所在的路径
        如果通过 IDEA 右上角的绿色三角符号运行,基准路径就是整个项目下的路径「和src统计目录」
         */
        File f1 = new File("./test.txt");
        System.out.println(f1.getParent());
        System.out.println(f1.getName());
        System.out.println(f1.getPath());
        System.out.println(f1.getAbsolutePath());
        System.out.println(f1.getCanonicalPath());
    }
}
// 运行结果:
/Users/cxf/java/4.System/src/file/content
test.txt
/Users/cxf/java/4.System/src/file/content/test.txt
/Users/cxf/java/4.System/ /Users/cxf/java/4.System/src/file/content/test.txt
/Users/cxf/java/4.System/ /Users/cxf/java/4.System/src/file/content/test.txt
**********
.
test.txt
./test.txt
/Users/cxf/java/4.System/./test.txt
/Users/cxf/java/4.System/test.txt

1.2 创建文件

package file;

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

public class Demo2 {
    public static void main(String[] args) throws IOException {
        File f = new File("./test.txt");
        System.out.println(f.exists());
        System.out.println(f.isDirectory());
        System.out.println(f.isFile());
        System.out.println("**********");
        // 创建一个文件
        System.out.println(f.createNewFile());
        System.out.println(f.exists());
        System.out.println(f.isDirectory());
        System.out.println(f.isFile());
    }
}
// 运行结果:
true
false
true
**********
false
true
false
true

1.3 删除文件

「立即删除」

package file;

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

// 文件删除
public class Demo3 {
    public static void main(String[] args) throws IOException {
        File f = new File("./deleted.txt");
        System.out.println(f.exists());
        System.out.println("创建文件之前");
        System.out.println("**********");
        System.out.println(f.createNewFile());
        System.out.println("创建文件之后");
        System.out.println(f.exists());
        System.out.println("删除文件之前");
        f.delete();
        System.out.println("删除文件之后");
        System.out.println(f.exists());
    }
}

// 运行结果:
false
创建文件之前
**********
true
创建文件之后
true
删除文件之前
删除文件之后
false

「删除动作会在JVM运行结束的时候执行」

package file;

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

public class Demo4 {
    public static void main(String[] args) throws IOException {
        File f = new File("./delete.txt");
        f.createNewFile();
        f.deleteOnExit();
        // 在这里加一个阻塞,方便看到
        new Scanner(System.in).nextInt();
    }
}

1.4 创建目录

package file;

import java.io.File;

public class Demo5 {
    public static void main(String[] args) {
        File f=new File("./src/file/content/testDir");
        /*
        mkdir:创建单个目录
        mkdirs:还会创建中间的文件夹目录
         */
        f.mkdirs();
    }
}

返回值类型函数意义
StringgetParent返回File对象的父目录
StringgetName返回File对象的纯文件名
StringgetPath返回File对象的文件夹路径
StringgetAbsolutePath返回File对象的绝对路径
StringgetCanonicalPath返回File对象修饰过的绝对路径
booleanexists判断File对象是否存在
booleanisFile判断File对象是否是文件
booleanisDirectory判断File对象是否是目录
booleancreateNewFile根据File对象创建一个新文件,成功返回true
booleandelete根据File对象删除文件,成功返回 true
voiddeleteOnExit根据File对象删除文件,删除动作会在JVM运行结束的时候执行
String[ ]list返回File对象下的所有文件名
File[ ]listFiles返回File对象下的所有文件,以File对象显示
booleanmkdir创建File对象的目录
booleanmkdirs创建File对象的目录,回创建中间目录
booleanrenameTo(File dest)文件改名,相当于剪切,粘贴操作
booleancanRead判断用户对文件是否有读权限
booleancanWrite判断用户对文件是否有写权限

1.5 文件改名

package file;

import java.io.File;

public class Demo6 {
    public static void main(String[] args) {
        File f = new File("./src/file/content/test.txt");
        File f1 = new File("./src/file/content/test.txt");
        f.renameTo(f1);
    }
}

2. 文件的读写

  • 字节流:以字节为单位,针对二进制文件「InputStream:负责读;OutputStream:负责写」
  • 字符流:以字符为单位,针对文本「Reader:负责读;Writer:负责写」

2.1 字节流读

package file;

import java.io.*;

// 字节流读取文件
public class Demo7 {
    public static void main(String[] args) {
        /*
        InputStream:是一个抽象类,是总领全局的,表示所有的按二进制读取文件的类
        构造方法中参数:
            打开的文件名:相对路径/绝对路径
            也可以是一个 File 对象
         */
//        InputStream inputStream = null;
//        try {
//            inputStream = new FileInputStream("./src/file/content/test.txt");
//            OutputStream outputStream = new FileOutputStream("./src/file/content/write.txt");
//            while (true) {
//                /*
//                用 int 而不是用 byte 是因为:读出来的数据范围[0, 255]
//                -1代表读完了
//                byte[-127, 128],一个字节
//                 */
//                int b = inputStream.read();
//                if (b == -1) {
//                    break;
//                }
//                System.out.println(b);
//            }
//        } catch (IOException e) {
//            e.printStackTrace();
//        } finally {
//            // 把 close 放在 finally 中保证即使代码出现异常也能关闭,但是代码看的太不方便
//            try {
//                inputStream.close();
//            } catch (IOException e) {
//                e.printStackTrace();
//            }
//        }

        // try white resources 把要释放的资源放到 try() 然后就会自动调用到关闭:要求 try() 里的对象能够实现 Closeable 接口。文件流对象都是实现了 Closeable
        try (InputStream inputStream = new FileInputStream("./src/file/content/test.txt")) {
            while (true) {
                int b = inputStream.read();
                if (b == -1) {
                    break;
                }
                System.out.println(b);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

代码是对上述注释代码的优化

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KL297VmG-1650273296486)(/Users/cxf/Desktop/MarkDown/images/InputStream_read.png)]

  • read:一次读一个字节
  • read(byte[] b):一次读若干个字节,尽可能的填满这个字节数组
    • 如果文件中剩余的数据比较多,超过了数组的长度,就会直接返回数组长度(把数组填满)
    • 如果文件中剩余的数据比较少,不超过参数数组的长度,此时就会直接返回时记得元素个数
  • read(byte[] b, int off, int len):加了一个起始和终止

为何选用int而不是byte接受inputStream

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8KntzqcV-1650273296488)(/Users/cxf/Desktop/MarkDown/images/为何选用int而不是byte接受inputStream.png)]

byte[-127, 128]

而读取数据遇到中文等特殊字符用的是 Unicode编码,而数据范围已经由之前的 ASCII码进行扩展,最大支持 128,已经无法满足,所以需要 255 来支撑

按照指定字节数读取

package file;

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

public class Demo8 {
    public static void main(String[] args) {
        // 尝试一次读取 1024 个字节
        try (InputStream inputStream = new FileInputStream("./src/file/content/test.txt")) {
            byte[] buffer = new byte[1024];
            while (true) {
                int len = inputStream.read(buffer);
                if (len == -1) {
                    break;
                }
                // 遍历每个字节
//                for (int b:buffer) {
//                    System.out.print(b);
//                }
                String s = new String(buffer, 0, len, "UTF-8");
                System.out.println(s);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2.2 字符流读

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-X0RLPYCE-1650273296489)(/Users/cxf/Desktop/MarkDown/images/FileReader_read.png)]

package file;

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

public class Demo9 {
    public static void main(String[] args) {
        try(Reader reader=new FileReader("./src/file/content/test.txt")){
            while (true){
                int c=reader.read();
                if (c==-1){
                    break;
                }
                System.out.print((char)c);
            }
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

读字符,一次读的是一个 char;读字节,一次读的是一个 byte

2.3 字节流写

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gLae0V3Y-1650273296490)(/Users/cxf/Desktop/MarkDown/images/FileoutputStream_write.png)]

package file;

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

public class Demo10 {
    public static void main(String[] args) {
        try (OutputStream outputStream = new FileOutputStream("./src/file/content/test.txt")) {
            // 使用 write 会清空原始数据
            outputStream.write(65);
            outputStream.write(66);
            outputStream.write(67);
            outputStream.write(68);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2.4 字符流写

OutputStream.write()可传入的参数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iAZRCRPw-1650273296490)(/Users/cxf/Desktop/MarkDown/images/FileWriter_write.png)]

package file;

import java.io.*;

public class Demo11 {
    public static void main(String[] args) {
        try (Writer writer = new FileWriter("./src/file/content/test.txt")) {
            writer.write('朱');
            writer.write("🐷");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

3. 案例

3.1 删除指定文件

package file;

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

// 根据指定的路径,堆路径进行遍历,删除符合要求的文件
public class Demo12 {
    public static void main(String[] args) throws IOException {
        Scanner scanner = new Scanner(System.in);
        // 1.提示用户输入一个带扫描的路径
        System.out.print("请输入要扫描的目录路径:");
        String rootDirPath = scanner.next();
        // 2.约定一下这个路径是否合法
        File rootDir = new File(rootDirPath);
        if (!rootDir.isDirectory()) {
            // 如果给定的这个路径不存在,或者不是目录,就直接出错
            System.out.println("您输入的扫描路径非法");
            return;
        }
        // 3.输入要删除的文件
        System.out.print("请输入要删除的文件名:");
        String deleteFileName = scanner.next();
        // 4.遍历当前目录,找到所有文件名和带删除文件名匹配的文件
        List<File> result = new ArrayList<>();
        // 通过 scanDir 这个方法把所有和 deleteFileName 匹配的文件都给找出来,放到 result 中「这个遍历文件的过程就需要用到递归」
        scanDir(rootDir, deleteFileName, result);
        // 5.进行删除,把 result 里找到的所有文件,都依次进行删除
        for (File f : result) {
            System.out.print(f.getCanonicalPath() + "该文件是否确认删除?y/n");
            String choice = scanner.next();
            if ("y".equals(choice) || "Y".equals(choice)) {
                f.delete();
                System.out.println(f.getCanonicalPath() + "删除成功");
            }
        }
    }

    private static void scanDir(File rootDir, String deleteFileName, List<File> result) throws IOException {
        // 1. 首先,先罗列出 rootDir 下都有哪些文件
        File[] files = rootDir.listFiles();
        for (File f : files) {
            System.out.println("扫描到了文件:" + f.getCanonicalPath());
            if (f.isFile()) {
                // 是普通文件
                if (f.getName().equals(deleteFileName)) {
                    result.add(f);
                }
            } else if (f.isDirectory()) {
                // 是目录,递归调用 scnDir 方法,针对这个目录,在进行进一步的判定
                scanDir(f, deleteFileName, result);
            }
        }
    }
}

3.2 文件拷贝

package file;

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

// 文件拷贝
public class Demo13 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.print("请输入复制的源文件:");
        String src = scanner.next();
        System.out.print("请输入要复制的目标文件");
        String dst = scanner.next();

        // 判定一下 src 是否存在
        File srcFile = new File(src);
        if (!srcFile.isFile()) {
            System.out.println("当前输入的路径有误,不是一个合法的路径!");
            return;
        }

        // 进行复制操作「打开src,把内容一个字节一个字节写入」
        try (InputStream inputStream = new FileInputStream(src); OutputStream outputStream = new FileOutputStream(dst)) {
            // 每次尝试读一个 byte[],把这整个数组都给写过去
            byte[] buffer = new byte[1024];
            while (true) {
                int len = inputStream.read(buffer);
                if (len == -1) {
                    break;
                }
                // 读取成功,写入到 outputStream 中
                outputStream.write(buffer, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

3.3 查找目录下是否包含某个字符串

package file;

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

// 在指定目录中查找包含制定字符串的文件「比较低效的代码」
public class Demo14 {
    public static void main(String[] args) throws IOException {
        Scanner scanner = new Scanner(System.in);
        // 1. 先输入要获取到的目录和内容
        System.out.print("请输入要遍历的目录:");
        String rootDirPath = scanner.next();
        System.out.print("请输入要查找的字符串:");
        String content = scanner.next();
        File rootDir = new File(rootDirPath);
        if (!rootDir.isDirectory()) {
            System.out.println("输入的路径存在问题!");
            return;
        }
        // 2.进行递归遍历,找到所有符合要求的文件
        List<File> results = new ArrayList<>();
        scanDirWithContent(rootDir, content, results);
        // 3.打印一下找到的文件结果
        for (File f : results) {
            System.out.println(f.getCanonicalPath());
        }
    }

    private static void scanDirWithContent(File rootDir, String content, List<File> results) {
        // 1.先列出 rootDir 中所有的文件
        File[] files = rootDir.listFiles();
        if (files == null){
            // 空目录
            return;
        }
        // 2.依次遍历每个文件,进行判定,如果是目录就进行递归
        for (File f : files) {
            if (f.isFile()) {
                // 如果是普通文件,就判定一下 content 是否被这个文件包含
                if (isContainsExist(f, content)) {
                    // 如果条件为 true,说明文件 f 包含 content,添加到 results
                    results.add(f);
                }
            } else if (f.isDirectory()) {
                // 是目录就递归
                scanDirWithContent(f, content, results);
            }
        }
    }

    private static boolean isContainsExist(File f, String content) {
        // 1.读取 f 的内容,把内容放到一个 String 类
        StringBuilder stringBuilder = new StringBuilder();
        try (Reader reader = new FileReader(f)) {
            while (true) {
                int c = reader.read();
                if (c == -1) {
                    break;
                }
                stringBuilder.append((char) c);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 2.判定 content 是否是读取的 String 的子串
        return stringBuilder.indexOf(content) != -1;
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值