Java中的文件操作(基础知识+三个小程序练习)

文件操作

关于文件,自然不用多说。狭义上的文件。针对硬盘这种持久化存储的I/O设备,当我们想要进行数据保存时,往往不是保存成一个整体,而是独立成一个个的单位进行保存,这个独立的单位就被抽象成文件的概念,就类似办公桌上的一份份真实的文件一般。

文件除了有数据内容之外,还有一部分信息,例如文件名、文件类型、文件大小等并不作为文件的数据而存在,我们把这部分信息可以视为文件的元信息。

文件的路径分为绝对路径相对路径

以盘符开头的路径为绝对路径,如:D:\program\qq\Bin\QQ.exe

以 . 或 … 开头的路径为相对路径,如: .\test.txt

Java中的文件操作

Java 中通过 java.io.File 类来对一个文件(包括目录)进行抽象的描述。

注意,有 File 对象,并不代表真实存在该文件

1 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()判断用户是否对文件有可写权限
1.1 代码示例

示例一:get系列

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.getCanonicalPath());
    }
image-20220805204648916

示例二:判断文件是否存在,判断文件、目录,创建文件

public static void main(String[] args) throws IOException {
        // 前面没写 './' ,也相当于是'./'  ('./' 可以省略)
        File file = new File("helloworld.txt");
        System.out.println(file.exists());
        System.out.println(file.isDirectory());
        System.out.println(file.isFile());
        System.out.println("=============");
        //创建文件
        file.createNewFile();
        System.out.println(file.exists());
        System.out.println(file.isDirectory());
        System.out.println(file.isFile());

示例三:删除文件

public static void main(String[] args) throws InterruptedException {
        //文件删除
        File file = new File("helloworld.txt");
        //file.delete();  立即删除

        Thread.sleep(5000);
        file.deleteOnExit();//程序退出时才删除(用来创建一些临时文件)
        System.out.println(file.exists());

    }

示例四:创建目录

//创建目录
    public static void main(String[] args) {
        File file = new File("test");
        System.out.println(file.exists());
        System.out.println(file.isDirectory());
        System.out.println("================");
        file.mkdir();
        System.out.println(file.exists());
        System.out.println(file.isDirectory());
        //创建多级目录
        //File file = new File("test/aa/1");
        //file.mkdirs();
    }

示例五:文件重命名

//文件重命名
    public static void main(String[] args) {
        File file1 = new File("./test.txt");
        File file2 = new File("./test2.txt");
        file1.renameTo(file2);// 用 file2 的名字给 file1 命名
    }

2 文件的读写操作——数据流

image-20220805205420144
2.1 读文件

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

read的不同使用方式

image-20220805210931307

利用FileInputStream进行读取文件

示例一

我们为了能让close一定被执行,这样做

    public static void main(String[] args)  {
        //使用一下 InputStream
        InputStream inputStream = null;
        try {
            //1.打开文件
            inputStream = new FileInputStream("./test2.txt");

            //2.读取文件
//        while(true){
//            int b = inputStream.read();
//            if(b == -1){
//                //文件读完了
//                break;
//            }
//            System.out.println(b);
//        }

            byte[] b = new byte[1024];
            int len = inputStream.read(b);
//        System.out.println(len);
//        for (int i = 0; i < len; i++) {
//            System.out.println(b[i]);
//        }
            String s = new String(b,0,len,"utf8");
            System.out.println(s);
        } catch (IOException e ){
            e.printStackTrace();
        } finally {
            //3.关闭文件
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

image-20220805210346592

但是在finally里还有个try-catch 会让代码很冗杂

我们这样做

public static void main(String[] args)  {
        try(InputStream inputStream = new FileInputStream("test2.txt")){
            //读文件
            byte[] b = new byte[1024];
            int len = inputStream.read(b);
            String s = new String(b,0,len,"utf8");
            System.out.println(s);
        }catch (IOException e){
            e.printStackTrace();
        }
    }

image-20220805210136730

代码二更为推荐

示例二:

当文件中的内容为 hello

image-20220805210416261

image-20220805210438839

使用Reader字符流读取文件

当文件中的内容变成了汉字:你好

image-20220805210529315

代码:

//使用字符流读一下文件
    public static void main(String[] args) throws IOException {
        Reader reader = new FileReader("test2.txt");
        char[] buffer = new char[1024];
        int len = reader.read(buffer);
        for(int i = 0; i< len; i++){
            System.out.println(buffer[i]);
        }
        reader.close();
    }

我们还有更简单的方法

利用 Scanner 进行字符读取

代码

// 对于文本文件  我们还有更简单的写法
    public static void main(String[] args) throws IOException {
        InputStream inputStream = new FileInputStream("test2.txt");

        Scanner scanner = new Scanner(inputStream);
        String s = scanner.next();
        System.out.println(s);

        inputStream.close();
    }
2.2 写文件

字节流:OutputStream/FileOutputStream

字符流:Writer/FileWriter

和 Scanner相对的,还可以使用 PrintWriter 来简化针对字符流的写入操作

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

利用 OutputStreamWriter 进行字符写入

一个字符一个字符地写

public static void main(String[] args) {
        try(OutputStream outputStream = new FileOutputStream("test2.txt")){
            outputStream.write('h');
            outputStream.write('e');
            outputStream.write('l');
            outputStream.write('l');
            outputStream.write('o');
        }catch (IOException e){
            e.printStackTrace();
        }
    }

写入一个字符串

 public static void main(String[] args) {
        try(OutputStream outputStream = new FileOutputStream("test2.txt")){
            String s = "hello java";
            outputStream.write(s.getBytes());

        }catch (IOException e){
            e.printStackTrace();
        }
    }

我们发现,每次写的时候都会把原本文件中的内容清空

image-20220806104128254

是因为这行代码

使用Writer进行字符流写入

示例

public static void main(String[] args) {
        try(Writer writer = new FileWriter("test2.txt")){
            writer.write("hello world");
        }catch (IOException e){
            e.printStackTrace();
        }
    }
利用 PrintWriter 进行字符写入
public static void main(String[] args) {
        try (OutputStream outputStream = new FileOutputStream("test2.txt")){
            PrintWriter printWriter = new PrintWriter(outputStream);
            printWriter.print("hello");
            printWriter.flush();
        }catch (IOException e){
            e.printStackTrace();
        }
    }

我们发现,与上面的方法不同的是 多了个 printWriter.flush();

解释:PrintWriter是自带了缓冲区的,所谓的缓冲区其实就是一块内存空间

那么缓冲区里的内容什么时候会被刷新到硬盘中呢?

  1. 缓冲区满了时
  2. 显式调用 flush (“冲水操作”)

所以在使用PrintWriter 时,别忘了要 flush

3 小程序练习

我们学会了文件的基本操作 + 文件内容读写操作,接下来,我们实现一些小工具程序,来锻炼我们的能力

3.1 文件查找并删除

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

如何遍历目录?

"递归"的把这里所有的文件(子目录中的文件)都能够访问到

public class Demo13 {
    //实现一个递归遍历文件,并询问删除
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入要扫描的路径");
        String rootPath = scanner.next();
        File root = new File(rootPath);
        if(!root.exists()){
            System.out.println("路径不存在");
            return;
        }
        System.out.println("请输入要删除的文件的文件名或者文件名的一部分");
        String toDelete = scanner.next();

        //准备进行递归  通过递归的方式找到所有的文件
        //找到所有的文件之后 再尝试进行删除
        scanDir(root,toDelete);

    }

    /**
     * 扫描目录
     * @param rootDir
     * @param toDelete
     */
    public static void scanDir(File rootDir,String toDelete){
        //加上个日志  看一下这里当前递归的过程
        try{
            System.out.println(rootDir.getCanonicalPath());
        }catch (IOException e){
            e.printStackTrace();
        }
        File[] files = rootDir.listFiles();
        if(files == null){
            //空目录 直接返回
            return;
        }
        for(File f : files){
            if(f.isDirectory()){
                //是目录 就继续递归
                scanDir(f,toDelete);
            }else {
                //普通文件
                tryDelete(f,toDelete);
            }
        }
    }
    public static void tryDelete(File f , String toDelete){
        //查看当前文件名是否包含了 toDelete 如果包含就删除,否则什么都不做
        if(f.getName().contains(toDelete)){
            try{
                System.out.println("是否要删除文件(Y/N):"+ f.getCanonicalPath());
                Scanner scanner = new Scanner(System.in);
                String choice = scanner.next();
                if(choice.equals("Y")){
                    f.delete();
                }
            }catch (IOException e){
                e.printStackTrace();
            }
        }
    }
}

上述过程其实就是一个 “深度优先遍历/搜索”

3.2 复制一个普通文件

普通文件,即:不是目录文件

把文件1复制成文件2

把文件1里的内容都按照字节读取出来,写入到文件2中

//实现复制文件的功能
    public static void main(String[] args) {
        //
        //准备工作
        //

        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入要复制的文件路径:");
        String srcPath = scanner.next();
        File srcFile = new File(srcPath);
        if(!srcFile.exists()){
            System.out.println("文件不存在");
            return;
        }
        if(!srcFile.isFile()){
            System.out.println("要复制的不是普通文件");
            return;
        }
        System.out.println("请输入要复制到的目标路径");
        String destPath = scanner.next();
        File destFile = new File(destPath);
        if(destFile.exists()){
            System.out.println("要复制到的目标已存在");
            return;
        }
        //
        //进行拷贝工作
        //
        try(InputStream inputStream = new FileInputStream(srcFile)) {
            try(OutputStream outputStream = new FileOutputStream(destFile)){
                byte[] buf = new byte[1024];
                while (true){
                    int len = inputStream.read(buf);
                    if(len == -1){
                        //拷贝完成
                        break;
                    }
                    outputStream.write(buf,0,len);
                }
            }
        }catch (IOException e){
            e.printStackTrace();
        }
        System.out.println("复制完成!");
    }

可以这样想象,在读文件的时候,在文件对象内部,有一个"光标",通过这个"光标"表示当前文件读到哪个位置了。

每次读操作,都会让光标往后移动, 直到文件末尾,再继续读,就会读到一个特殊的字符, EOF

3.3 文件深层查找(名称/内容)
public class Demo15 {
    //遍历目录,看某个输入的词是否在文件名或者文件内容中存在
    public static void main(String[] args) throws IOException {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入要搜索的目录:");
        String rootPath = scanner.next();
        File rootFile = new File(rootPath);
        if(!rootFile.exists()){
            System.out.println("该目录不存在");
            return;
        }
        if(!rootFile.isDirectory()){
            System.out.println("该路径不是目录");
            return;
        }
        System.out.println("请输入要搜索的关键词:");
        String toFind = scanner.next();

        //递归遍历目录
        scanDir(rootFile,toFind);
    }

    private static void scanDir(File rootFile, String toFind) throws IOException {
        File[] files = rootFile.listFiles();
        if(files == null){
            return;
        }
        for (File f : files) {
            if(f.isDirectory()){
                scanDir(f,toFind);
            }else {
                tryFindInFile(f,toFind);
            }
        }
    }

    //判定toFind是否是文件名或者是文件内容的一部分
    private static void tryFindInFile(File f, String toFind) throws IOException {
        //是不是文件名的一部分
        if(f.getName().contains(toFind)){
            System.out.println("找到了文件名与关键词匹配的文件:"+f.getCanonicalPath());
            return;
        }
        //是不是文件内容的一部分
        try(InputStream inputStream = new FileInputStream(f)){
            //把文件内容整个都读出来
            StringBuilder stringBuilder = new StringBuilder();
            Scanner scanner = new Scanner(inputStream);
            while (scanner.hasNextLine()){
                stringBuilder.append(scanner.nextLine());
            }
            //读取完毕了
            if(stringBuilder.indexOf(toFind) >= 0){
                System.out.println("找到了文件内容与关键词匹配的文件:"+f.getCanonicalPath());
                return;
            }
        }
    }
}

注:我们现在的方案性能较差,所以尽量不要在太复杂的目录下或者大文件下实验

  • 16
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
题目从一个txt文件读取一系列学生的信息(包括姓名、年龄和成绩),按照成绩从高到低排列,并输出到另一个txt文件。 首先,我们可以使用Java文件读写操作来读取txt文件的学生信息。我们可以使用BufferedReader类的readLine()方法来逐行读取txt文件的内容。 接下来,我们可以使用ArrayList来存储学生的信息。我们可以创建一个自定义的学生类,包含姓名、年龄和成绩等属性。然后,可以通过循环读取txt文件的每一行,并将每个学生的信息存储到ArrayList。 在读取过程,我们可以使用String类的split()方法将每行的信息分割成相应的属性。然后,可以创建一个学生对象,并将读取到的属性赋值给对象的成员变量。 然后,我们可以使用Comparator接口来定义比较器。通过重写Compare方法,我们可以按照学生对象的成绩进行比较,并将成绩从高到低排序。 最后,我们可以使用Collections.sort()方法对ArrayList进行排序操作,并输出到另一个txt文件。我们可以使用BufferedWriter类将学生的信息写入到新的txt文件。 需要注意的是,在读取和写入文件时,我们需要处理异常。可以使用try-catch语句来捕获可能发生的异常,并在发生异常时输出错误信息。 总的来说,以上是完成该Java编程题的一种方法。通过文件读写操作、ArrayList和排序等Java知识,我们可以实现从一个txt文件读取学生信息并按成绩从高到低排列的功能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值