【JavaEE多线程】Java 文件操作

目录

    • Java中操作文件
      • File概述
        • 属性
        • 构造方法
        • 方法
      • 文件内容的读写——文件流 stream
        • InputStream
        • FileInputStream概述
        • 利用 Scanner 进行字符读取
        • OutputStream 概述
      • 练习


Java中操作文件

Java 中通过 java.io.File类来对一个文件(包括目录)进行抽象的描述。注意,有 File 对象,并不代表真实存在该文件。

文件系统操作

创建文件、删除文件、创建目录

通过File对象来描述一个具体的文件,File对象可以对应到一个真实存在的文件,也可以对应到一个不存在的文件

File概述

属性
修饰符及类型属性说明
static StringpathSeparator依赖于系统的路径分隔符,String 类型的表示
static charpathSeparator依赖于系统的路径分隔符,char 类型的表示
构造方法
签名说明
File(File parent, String child)根据父目录 + 孩子文件路径,创建一个新的 File 实例
File(String pathname)根据文件路径创建一个新的 File 实例,路径可以是绝对路径或者相对路径
File(String parent, String child)根据父目录 + 孩子文件路径,创建一个新的 File 实例,父目录用路径表示
方法
修饰符及返回值类型方法签名说明
StringgetParent()返回 File 对象的父目录文件路径
StringgetName()返回 FIle 对象的纯文件名称
StringgetPath()返回 File 对象的文件路径
StringgetAbsolutePath()返回 File 对象的绝对路径
StringgetCanonicalPath()返回 File 对象的修饰过的绝对路径
booleanexists()判断 File 对象描述的文件是否真实存在
booleanisDirectory()判断 File 对象代表的文件是否是一个目录
booleanisFile()判断 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()判断用户是否对文件有可写权限

观察 get 系列的特点和差异

//File的使用
public class Demo1 {
    public static void main(String[] args) throws IOException {
        File file=new File("./test.txt");
        System.out.println(file.getParent());
        System.out.println(file.getName());
        System.out.println(file.getPath());
        System.out.println(file.getAbsolutePath());
        System.out.println(file.getCanonicalFile());
    }
}

//运行结果
.
test.txt
.\test.txt
C:\Users\幽琴健\java_Code\giteedemo\system_code\.\test.txt
C:\Users\幽琴健\java_Code\giteedemo\system_code\test.txt

普通文件的创建

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

        //创建文件
        file.createNewFile();

        System.out.println(file.exists());
        System.out.println(file.isFile());
        System.out.println(file.isDirectory());
    }
}

//运行结果
true
true
false

普通文件的删除

//文件删除
public class Demo3 {
    public static void main(String[] args) throws InterruptedException, IOException {
        File file =new File("./test.txt");
        System.out.println(file.createNewFile());
        //System.out.println(file.delete());

        //是等到程序退出了再删除,不是立即删除;
        file.deleteOnExit();
        System.out.println(file.exists());
        Thread.sleep(5000);
    }
}

//运行结果
true
true

观察目录的创建1

public class Demo4 {
    public static void main(String[] args) {
        File file=new File("./testDir");// 要求该目录不存在,才能看到相同的现象

        System.out.println(file.mkdir());
        System.out.println(file.isDirectory());
    }
}

//运行结果
true
true

观察目录的创建2

public class Demo4 {
    public static void main(String[] args) {
        File file=new File("./testDir/111/222/333");// 要求该目录不存在,才能看到相同的现象

        System.out.println(file.mkdirs());
        System.out.println(file.isDirectory());
    }
}

//运行结果
true
true

观察文件重命名

//文件重命名
public class Demo5 {
    public static void main(String[] args) {
        File file=new File("./test.txt");
        File file2=new File("./test1.txt");
        System.out.println(file.renameTo(file2));
    }
}

//运行结果
true

以上文件系统的操作,都是基于File类来完成的。另外还需要文件内容的操作

文件内容的读写——文件流 stream

文件这里的内容本质是来自于硬盘,硬盘又是操作系统管理的。使用某个编程语言操作文件,本质上都是需要调用系统的api

文件内容的操作核心步骤有四个:

  1. 打开文件 fopen
  2. 关闭文件 fclose
  3. 读文件 fread
  4. 写文件 fwrite

字节流:InputStream、OutputStream,是操作字节为单位(二进制文件)

字符流:Reader、Writer,是操作字符为单位(文本文件)

Java lO 流是一个比较庞大的体系,涉及到非常多的类。这些不同类,都有各自不同的特性但是总的来说,使用方法都是类似的。

  1. 构造方法,打开文件
  2. close方法,关闭文件。(可以通过finally或者**try()**的方式去关闭,后者更优雅)
  3. 如果衍生自InputStream或者Reader就可以使用read方法来读数据
  4. 如果衍生自OutputStream或者Writer就可以使用write方法来写数据

注意:close()方法这个释放必要的资源这个操作非常重要。让一个进程打开一个文件是要从系统这里申请一定的资源的(占用进程的PCB里的文件描述符表中的一个表项,这个表是个顺序表,长度有限且不会扩容),如果不释放就会出现“文件资源泄露”,如果一直打开,文件描述符表就会被占满,后续就无法继续打开新的文件了

文本文件也可以用字节流打开,只不过此时你读到的每个字节就不是完整的字符了

InputStream

方法

修饰符及返回值类型方法签名说明
intread()读取一个字节的数据,返回 -1 代表已经完全读完了
intread(byte[] b)最多读取 b.length 字节的数据到 b 中,返回实际读到的数量;-1 代表以及读完了
intread(byte[] b,int off, int len)最多读取 len - off 字节的数据到 b 中,放在从 off 开始,返回实际读到的数量;-1 代表以及读完了
voidclose()关闭字节流

说明

InputStream 只是一个抽象类,要使用还需要具体的实现类。关于 InputStream 的实现类有很多,基本可以认为不同的输入设备都可以对应一个 InputStream 类,我们现在只关心从文件中读取,所以使用FileInputStream

FileInputStream概述

构造方法

签名说明
FileInputStream(File file)利用 File 构造文件输入流
FileInputStream(String name)利用文件路径构造文件输入流
//Reader使用
public class Demo6 {
    public static void main(String[] args) throws IOException {
//        FileReader 构造方法, 可以填写一个文件路径(绝对路径/相对路径都行), 也可以填写一个构造好的 File 对象
//        Reader reader = new FileReader("d:/test.txt");
//        try {
//            // 中间的代码无论出现啥情况, close 都能保证执行到.
//        } finally {
//            // 抛出异常, 或者 return, close 就都执行不到了~~
//            reader.close();
//        }

        // 上述使用 finally 的方式能解决问题, 但是不优雅.
        // 使用 try with resources 是更好的解决方案.
        try(Reader reader=new FileReader("d:/test.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]+" ");
                }
            }
        }

    }
}
public class Demo7 {
    public static void main(String[] args) throws IOException {
        try (InputStream inputStream = new FileInputStream("d:/test.txt")) {
            while (true) {
                byte[] buf = new byte[1024];
                int n = inputStream.read(buf);
                if (n == -1) {
                    break;
                }
                for (int i = 0; i < n; i++) {
                    System.out.printf("%x ", buf[i]);
                }
                String s = new String(buf, 0, n, "utf8");
                System.out.println(s);
            }
        }
    }
}
利用 Scanner 进行字符读取

上述例子中,我们看到了对字符类型直接使用 InputStream 进行读取是非常麻烦且困难的,所以,我们使用一种我们之前比较熟悉的类来完成该工作,就是 Scanner 类。

构造方法说明
Scanner(InputStream is, String charset)使用 charset 字符集进行 is 的扫描读取
public class Demo8 {
    public static void main(String[] args) throws IOException {
        try(InputStream inputStream=new FileInputStream("d:/test.txt")){
            Scanner scanner=new Scanner(inputStream);
            //此时就是从test.txt这个文件中读取数据了
            String s=scanner.next();
            System.out.println(s);
        }
    }
}
OutputStream 概述

方法

修饰符及返回值类型方法签名说明
voidwrite(int b)写入要给字节的数据
voidwrite(byte[] b)将 b 这个字符数组中的数据全部写入 os 中
intwrite(byte[] b, int off,int len)将 b 这个字符数组中从 off 开始的数据写入 os 中,一共写 len 个
voidclose()关闭字节流
voidflush()重要:我们知道 I/O 的速度是很慢的,所以,大多的 OutputStream 为了减少设备操作的次数,在写数据的时候都会将数据先暂时写入内存的一个指定区域里,直到该区域满了或者其他指定条件时才真正将数据写入设备中,这个区域一般称为缓冲区。但造成一个结果,就是我们写的数据,很可能会遗留一部分在缓冲区中。需要在最后或者合适的位置,调用 flush(刷新)操作,将数据刷到设备中。

说明

OutputStream 同样只是一个抽象类,要使用还需要具体的实现类。我们现在还是只关心写入文件中,所以使用 FileOutputStream

public class Demo9_1 {
    public static void main(String[] args) throws IOException {
        try(OutputStream outputStream=new FileOutputStream("d:/test.txt")){
            outputStream.write('H');
            outputStream.write('e');
            outputStream.write('l');
            outputStream.write('l');
            outputStream.write('o');

            //不要忘记了 flsuh()
            outputStream.flush();
        }
    }
}

练习

扫描指定目录,并找到名称中包含指定字符的所有普通文件(不包含目录),并且后续询问用户是否要删除该文件

public class Demo10 {
    private static Scanner scanner = new Scanner(System.in);

    public static void main(String[] args) {
        //1、让用户输入一个目录,后续的查找都是针对这个目录来进行的
        System.out.println("请输入要搜索的根目录:");
        File rootPath = new File(scanner.next());
        //2、再让用户输入要搜索/要删除的关键词
        System.out.println("请输入要删除的关键词:");
        String word = scanner.next();
        //3、判定一下当前要输入的目录是否有效
        if (!rootPath.isDirectory()) {
            System.out.println("您输入的路径不是合法目录");
            return;
        }
        //4、遍历目录,从根目录出发,按照深度优先(递归)的方式进行遍历
        scanDir(rootPath,word);
    }

    public static void scanDir(File curDir, String word) {
        //1、先列出当前目录中都包含哪些内容
        File[] files = curDir.listFiles();
        if (files == null || files.length == 0) {
            //非法目录或者空目录
            return;
        }
        //2、遍历列出的文件,分两种情况讨论
        for (File f : files) {
            //加个日志,方便查看程序执行的过程
            System.out.println(f.getAbsolutePath());

            if (f.isFile()) {
                //3、如果当前文件是普通文件,看看文件名是否包含了word,来决定是否要删除
                dealFile(f, word);
            } else {
                //4、如果当前文件是目录文件,就递归执行scanDir
                scanDir(f, word);
            }
        }
    }

    private static void dealFile(File f, String word) {
        //1、先判定当前文件名是否包含word
        if (!f.getName().contains(word)) {
            //此时这个文件不包含word关键词,直接跳过
            return;
        }
        //2、包含word就需要询问用户是否需要删除该文件?
        System.out.println("该文件是:" + f.getAbsolutePath() + ",是否确认删除(Y/N)");
        String choice = scanner.next();
        if (choice.equals("Y") || choice.equals("y")) {
            f.delete();
        }
        //如果是其他值就忽略
    }
}

//运行结果
请输入要搜索的根目录:
d:/tmp
请输入要删除的关键词:
test
d:\tmp\111
d:\tmp\111\aaa
d:\tmp\111\aaa\test.txt
该文件是:d:\tmp\111\aaa\test.txt,是否确认删除(Y/N)
n
d:\tmp\222
d:\tmp\222\bbb
d:\tmp\222\bbb\新建 文本文档.txt
d:\tmp\333
d:\tmp\333\ccc

进行普通文件的复制

public class Demo11 {
    public static void main(String[] args) throws IOException {
        Scanner scanner = new Scanner(System.in);
        //1、输入路径并且合法性判定
        System.out.println("请输入要复制的源文件路径:");
        String src = scanner.next();
        File srcFile = new File(src);
        if (!srcFile.isFile()) {
            System.out.println("您输入的源文件路径非法");
            return;
        }
        System.out.println("请输入要复制到的目标路径:");
        String dest = scanner.next();
        File destFile = new File(dest);
        //不要求目标文件本身存在. 但是得保证目标文件所在的目录, 得是存在的.
        //假设目标文件写作 d:/tmp/cat2.jpg, 就需要保证 d:/tmp 目录是存在的.
        if (!destFile.getParentFile().isDirectory()) {
            System.out.println("您输入的目标路径非法");
            return;
        }

        //2、进行复制操作的过程,按照字节流打开
        try (InputStream inputStream = new FileInputStream(srcFile);
             OutputStream outputStream = new FileOutputStream(destFile)) {
            while (true) {
                byte[] buffer = new byte[20480];
                int n = inputStream.read(buffer);
                System.out.println("n=" + n);
                if (n == -1) {
                    System.out.println("读取到EOF,循环结束");
                    break;
                }
                outputStream.write(buffer, 0, n);
            }
        }
    }
}

//运行结果
请输入要复制的源文件路径:
d:/tmp/111/calculator.png
请输入要复制到的目标路径:
d:/tmp/222/calculator2.png
n=20480
n=220
n=-1
读取到EOF,循环结束

扫描指定目录,并找到名称或者内容中包含指定字符的所有普通文件(不包含目录)

public class Demo12 {
    public static void main(String[] args) throws IOException {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入要扫描的根目录:");
        String rootPath = scanner.next();
        File rootDir = new File(rootPath);
        if (!rootDir.isDirectory()) {
            System.out.println("您输入的根目录不是非法目录");
            return;
        }

        System.out.println("请输入要找出的文件名中的字符");
        String token = scanner.next();

        List<File> result = new ArrayList<>();
        //因为文件系统是树形结构,所以我们使用深度优先遍历(递归)完成遍历
        scanDirWithContent(rootDir, token, result);
        System.out.println("共找到了符合条件的文件 " + result.size() + " 个,它们分别是:");

        for (File file : result) {
            System.out.println(file.getCanonicalFile());
        }
    }

    private static void scanDirWithContent(File rootDir, String token, List<File> result) throws IOException {
        File[] files = rootDir.listFiles();
        if (files == null || files.length == 0) {
            return;
        }

        for (File file : files) {
            if (file.isDirectory()) {
                scanDirWithContent(file, token, result);
            } else {
                if (isContentContains(file, token)) {
                    result.add(file.getAbsoluteFile());
                }
            }
        }
    }

    //我们全部按照utf-8的字符文件来处理
    private static boolean isContentContains(File file, String token) throws IOException {
        StringBuilder sb = new StringBuilder();
        try (InputStream inputStream = new FileInputStream(file)) {
            try (Scanner scanner = new Scanner(inputStream, "UTF-8")) {
                while (scanner.hasNextLine()) {
                    sb.append(scanner.nextLine());
                    sb.append("\r\n");
                }
            }
        }
        return sb.indexOf(token) != -1;
    }
}

//运行结果
请输入要扫描的根目录:
d:/tmp
请输入要找出的文件名中的字符
hello
共找到了符合条件的文件 3 个,它们分别是:
D:\tmp\111\aaa\test.txt
D:\tmp\222\bbb\新建 文本文档.txt
D:\tmp\333\ccc\新建 文本文档.txt

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/566910.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

GUI测试首推!TestComplete 帮助有效缩短 40-50% 测试时长!

TestComplete 是一款自动化UI测试工具&#xff0c;这款工具目前在全球范围内被广泛应用于进行桌面、移动和Web应用的自动化测试。 TestComplete 集成了一种精心设计的自动化引擎&#xff0c;可以自动记录和回放用户的操作&#xff0c;方便用户进行UI&#xff08;用户界面&…

C++ 面向对象-封装

C 是一种多范式编程语言&#xff0c;它支持面向对象编程&#xff08;OOP&#xff09;范式。面向对象编程是一种程序设计思想&#xff0c;其中程序由对象组成&#xff0c;每个对象都是一个实例&#xff0c;具有数据和相关操作。在C中&#xff0c;实现面向对象编程主要通过类和对…

Vue3、 Vue2 Diff算法比较

Vue2 Diff算法 源码位置:src/core/vdom/patch.ts 源码所在函数:updateChildren() 源码讲解: 有新旧两个节点数组:oldCh和newCh; 有下面几个变量: oldStartIdx 初始值=0 oldStartVnode 初始值=oldCh[0] oldEndIdx 初始值=oldCh.length - 1 oldEndVnode 初始值=oldCh[ol…

如何在PostgreSQL中设置定期任务(如定时备份、数据分析等),并使用pgAgent或其他方式实现

文章目录 使用pgAgent实现定期任务步骤一&#xff1a;安装pgAgent步骤二&#xff1a;配置pgAgent步骤三&#xff1a;创建和调度任务示例代码&#xff1a; 使用操作系统的任务调度功能实现定期任务步骤一&#xff1a;编写脚本步骤二&#xff1a;设置cron任务示例代码&#xff1a…

ssh日志的独立与ssh远程日志

日志相关介绍&#xff1a; 1.系统日志&#xff1a;是记录了历史事件&#xff1a;包括时间地点人物事件等。日志级别&#xff1a;事件的关键性程度&#xff0c;Loglevel。 级号消息级别说明0EMERG紧急会导致主机系统不可用的的情况1ALERT警告必须马上采取措施解决的问题2CRIT严…

vue3实现全局事件总线

1、vue3中使用全局事件总线是变化最大的。在vue2中&#xff0c;我们在new Vue中在beforeCreate钩子函数中使用vue.prototype.$busthis来创建全局事件总线。vue3中我需要借助第三方库来完成创建全局事件总线。 2、安装依赖 npm i mitt -s3、封装event-bus.js文件 import mitt …

【白菜学习问问问系列】if __name__ == ‘__main__‘:怎么理解

可以让.py文件既可以当成一个模块调用&#xff0c;也可以单独的作为一个函数执行

【基础算法】双指针

1.移动零 移动零 思路&#xff1a; 利用双指针算法 cur&#xff1a;从左往右扫描数组&#xff0c;遍历数组 dest&#xff1a;处理好的区间包括dest dest初始化为-1&#xff0c;因为刚开始dest前应该没有非零元素。 即将非零元素移到dest之前即可 class Solution { public…

2016年新华三杯复赛实验试题

2016年新华三杯复赛实验试题 拓扑图 配置需求 考生根据以下配置需求在 HCL 中的设备上进行相关配置。 以太网接口配置 将 S1、S2 的以太网接口 G1/0/1 至 G1/0/16 的模式用命令 combo enable copper 激活为电口。 虚拟局域网 为了减少广播&#xff0c;需要规划并配置 VLA…

浏览器工作原理与实践--HTTPS:浏览器如何验证数字证书

你好&#xff0c;我是李兵。 在《HTTPS&#xff1a;让数据传输更安全》这篇文章中&#xff0c;我们聊了下面几个问题&#xff1a; HTTPS使用了对称和非对称的混合加密方式&#xff0c;这解决了数据传输安全的问题&#xff1b; HTTPS引入了中间机构CA&#xff0c;CA通过给服务器…

重生奇迹mu卷轴有什么用

问题一&#xff1a;重生奇迹mu里面的国王卷轴有什么用啊?创造宝石怎么用啊?国王卷不晓得~~宝石用来创造果实的。&#xff08;属性果实&#xff09; 问题二&#xff1a;请问重生奇迹mu里国王卷轴去哪弄&#xff1f;天空之城有&#xff0c;废墟1和2也有&#xff0c;遗址230也有…

付费SSL证书比免费SSL证书好在哪?

1. 身份证明更权威&#xff1a;付费证书可进行深度身份验证&#xff0c;让访客知道你的网站是真实、合法的公司运营&#xff0c;尤其高级证书能在浏览器地址栏显示公司名&#xff0c;让人一看就放心。 2. 适用范围广&#xff1a;有单域名、多域名、通配符等多种证书类型&#x…

基于SpringBoot的“幼儿园管理系统”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“幼儿园管理系统”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 系统功能结构图 个人信息界面图 缴费信息管理界…

重温javascript --(一)值的介绍

值的介绍 一、 值类型&#xff1a; 原始值 stack栈: 遵循后进先出原则&#xff0c;中主要存放一些基本类型的变量和对象的引用。如&#xff1a;Number String Boolean undefined null symbol BigInt 栈内不可修改值&#xff0c;内存满才会实现二次值覆盖 引用值 heap堆&#x…

C盘满了如何清理

1.更改位置 &#xff08;1&#xff09;找到要更改的用户 &#xff08;2&#xff09;找到要更改的部分&#xff0c;右键点击“属性” &#xff08;3&#xff09;选择“位置”——“移动”——选择要移动的盘及地方 点击“确定”——“是”&#xff0c;等待迁移完成

STL_vector源码剖析

STL vector STL2.91源码地址: https://github.com/lewischeng-ms/sgi-stl 侯捷老师用的是 2.91,不同版本的STL差异很大&#xff0c;靠后版本的STL用了太多typedef以及继承关系&#xff0c;导致可读性很差。 本文参考博客: https://blog.csdn.net/weixin_45389639/article/detai…

Docker NetWork (网络)

Docker 为什么需要网络管理 容器的网络默认与宿主机及其他容器都是相互隔离的&#xff0c;但同时我们也要考虑下面的一些问题&#xff0c; 比如 多个容器之间是如何通信的容器和宿主机是如何通信的容器和外界主机是如何通信的容器中要运行一些网络应用(如 nginx、web 应用、数…

【Linux系统编程】第七弹---权限管理操作(上)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】 目录 1、修改文件权限的做法(一) 2、有无权限的表现 总结 上一弹我们讲解了Linux权限概念相关的知识&#xff0c;但是我们只知道有…

设计模式学习笔记 - 开源实战四(中):剖析Spring框架中用来支持扩展的设计模式

概述 上篇文章&#xff0c;学习了 Spring 框架背后蕴含的设计思想&#xff0c;比如约定优于配置、低侵入松耦合、模块化轻量级等等。这些设计思想可以借鉴到其他框架开发中&#xff0c;在大的设计层面提高框架的代码质量。 除了上篇文章降到的设计思想&#xff0c;实际上&…

yolov8 裁剪检测结果

yolov8 裁剪检测结果 1. 基础2. 图片批量裁剪2.1 检测裁剪2.2 分割裁剪 3. 视频裁剪3.1 检测裁剪3.2 分割裁剪3.3 实时裁剪 4. 源码 1. 基础 本项目是在 WindowsYOLOV8环境配置 的基础上实现的 思路&#xff1a;将检测得到的物体边框提取&#xff0c;然后边框裁剪原图&#xf…