【文件IO】实际应用举例

一、文件查找并删除

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

一个主要的操作就是需要扫描指定目录(递归)

递归函数

  1. 首先判断是否是目录,若不是,直接返回
  2. 若是,则列出当前目录的文件名,放到 files 数组中
  3. 如果 files 是空的,或者 files 数组长度为 0,代表没有文件,则直接返回
  4. 循环遍历 files 数组
    1. 若此时遍历到的文件是普通文件
      • 调用删除文件方法 doDelete
    2. 若磁石遍历到的仍是目录
      • 继续递归
public class Demo15 {  
    //递归目录的方法  
    private static void scan(File currentFile, String key) {  
        if(!currentFile.isDirectory()){  
            return;  
        }        
        File[] files = currentFile.listFiles();  
        if(files == null || files.length == 0){  
            return;  
        }        
        for(File f : files){  
            if(f.isFile()){  
                doDelete(f,key);  
            }else {  
                scan(f,key);  
            }        
        }    
    }
}

删除函数

  1. 文件名中不包含关键字,则直接返回
  2. 若包含,则提示用户,是否进行删除
  3. 用户输入 Y/N 进行选择
  4. 若输入为 Y y,则将此文件删除
private static void doDelete(File f, String key){  
    if(!f.getName().contains(key)){  
        return;  
    }    
    Scanner scanner = new Scanner(System.in);  
    System.out.println(f.getAbsolutePath()+"是否确定要删除 Y/N");  
    String choice = scanner.next();  
    if(choice.equals("Y") || choice.equals("y")) {  
        f.delete();  
    }
}

完整代码

import java.io.File;  
import java.util.Scanner;  
  
public class Demo15 {  
    //递归目录的方法  
    private static void scan(File currentFile, String key) {  
        if(!currentFile.isDirectory()){  
            return;  
        }        
        File[] files = currentFile.listFiles();  
        if(files == null || files.length == 0){  
            return;  
        }        
        for(File f : files){  
            if(f.isFile()){  
                doDelete(f,key);  
            }else {  
                scan(f,key);  
            }        
        }    
    }


    private static void doDelete(File f, String key){  
        if(!f.getName().contains(key)){  
            return;  
        }        
        Scanner scanner = new Scanner(System.in);  
        System.out.println(f.getAbsolutePath()+"是否确定要删除 Y/N");  
        String choice = scanner.next();  
        if(choice.equals("Y") || choice.equals("y")) {  
            f.delete();  
        }    
    }  

    public static void main(String[] args) {  
        System.out.println("请输入要搜索的路径:");  
        Scanner scanner = new Scanner(System.in);  
        String rootPath = scanner.next();  
        File rootFile = new File(rootPath);  
        if(!rootFile.isDirectory()){  
            System.out.println("输入的路径不存在");  
            return;  
        }        
        System.out.println("请输入要删除的文件名字的关键字:");  
        String key = scanner.next();  
  
        //进行递归查找  
        scan(rootFile,key);  
    }
}

二、文件复制

进⾏普通⽂件的复制

把一个文件里面的每个字节都读出来,再写入另一个文件中

  1. 输入源文件路径,并实例出一个 srcFile 对象
  2. 判断这个对象是否是一个文件,若不是,则返回
  3. 若是,则继续输入目标文件的路径
  4. 以这个路径实例化出一个 dextFile 文件
  5. 得到这个文件所在处的父目录,并判断其是否是一个目录
  6. 若是,则开始执行复制的过程
    • 通过 InputStream 进行读操作,OutputStream 进行写操作
import java.io.*;  
import java.util.Scanner;  
  
public class Demo16 {  
    public static void main(String[] args) throws IOException {  
        Scanner scanner = new Scanner(System.in);  
        System.out.println("请输入源文件路径:");  
        String srcPath = scanner.next();  
        File srcFile = new File(srcPath);  
        if(!srcFile.isFile()){  
            System.out.println("源文件路径有误!");  
            return;  
        }        
        System.out.println("请输入目标文件路径");  
        String destPath = scanner.next();  
        File destFile = new File(destPath);  
        if(!destFile.getParentFile().isDirectory()) {  
            System.out.println("输入的目标文件路径有误!");  
            return;  
        }  
        try(InputStream inputStream = new FileInputStream(srcFile);  
            OutputStream outputStream = new FileOutputStream(destFile)){  
            while (true) {  
                byte[] buffer = new byte[1024];  
                int n = inputStream.read(buffer);  
                if(n == -1){  
                    break;  
                }                
                outputStream.write(buffer,0,n);  
            }        
        }catch (IOException e){  
            e.printStackTrace();  
        }    
    }
}
  • try() 里面可以写多个对象,多个对象的构造过程使用 ; 分隔就可以了
  • 写入的时候,不能直接 write(buffer),因为前面读操作不一定能把 buffer 填满,若直接写入 buffer,就把没有用到的空间也写入了,不太合适
    • 也许 buffer 只填了 100 个空间,剩下 924 个空间都是 0,写入就没有意义
    • 此时我们就需要指定空间写入[0, n]

三、递归遍历目录查找文件

扫描指定⽬录,并找到名称或者内容中包含指定字符的所有普通⽂件(不包含⽬录) 注意:我们现在的⽅案性能较差,所以尽量不要在太复杂的⽬录下或者⼤⽂件下实验

import java.io.*;  
import java.util.Scanner;  
  
  
  
public class Demo17 {  
    public static void main(String[] args) {  
        Scanner scanner = new Scanner(System.in);  
        System.out.println("请输入要搜索的路径:");  
        String rootPath = scanner.next();  
        File rootFile = new File(rootPath);  
        if(!rootFile.isDirectory()){  
            System.out.println("要搜索的路径有误!");  
            return;  
        }        
        System.out.println("请输入要搜索的查询词:");  
        String key = scanner.next();  
  
        //进行递归查找  
        scan(rootFile,key);  
    }  
    private static void scan(File rootFile, String key) {  
        if(!rootFile.isDirectory()) {  
            return;  
        }        
        File[] files = rootFile.listFiles();  
        if(files.length == 0 || files == null) {  
            return;  
        }        
        for(File f : files) {  
            if(f.isFile()){  
                //进行后续的查询操作  
                doSearch(f,key);  
            }else{  
                scan(f,key);  
            }        
        }    
    }  
  
    private static void doSearch(File f, String key) {  
        //打开文件,读取文件内容,并判定文件内容是否包含 key        
        StringBuilder stringBuilder = new StringBuilder();  
        //因为不考虑二进制,直接按照文本的方式来处理,就直接用 Reader        
        try(Reader reader = new FileReader(f)){  
            char[] buffer = new char[1024];  
            while(true) {  
                int n = reader.read(buffer);  
                if(n == -1){  
                    break;  
                }                
                String s = new String(buffer,0,n);  
                stringBuilder.append(s);  
            }        
        }catch (IOException e){  
            e.printStackTrace();  
        }        
        if(stringBuilder.indexOf(key) == -1) {  
            //未找到  
            return;  
        }        
        //找到了  
        System.out.println("找到匹配的文件" + f.getAbsolutePath());  
    }
}
  • 这个代码逻辑效率很低,每次查询都会涉及到大量的硬盘 IO 操作,因为每次判定都要将硬盘里面的所有文件都读一遍。尤其是遇到硬盘上有些大的文件
  • 这种思路不能适应频繁查询场景,也不能适应目录中文件数目特别多,特别大的场景

咱们搜索引擎中,进行搜索的过程,也就是在文件中查找内容是否被包含的过程
搜索出来的结果其实就是一些 HTML 文件,这些 HTML 文件里面一定是包含你的查询词(或者和你的查询词有关的)

搜索引擎每次搜索都是在数以十亿,数以百亿的 HTMl 中,找到几十万,几百万个结果

搜索引擎这样的场景,不能通过上述“遍历文件”方式实现

  • 其中最核心的优化,是引入了神奇的数据结构——倒排索引
  • 提前把所有的文件,里面的内容都分析好,分析出一个文件中,包含哪些词,再基于这个结果,得到另一份数据,每个词都在哪些文件中包含着
    • 之后就是一个查询哈希表的过程
    • 主要的难点就是这个哈希表如何来

在未来实际工作中,也会用到一些“自定制的搜索引擎”
比如,我们自己的代码中,产生大量的日志,把这些日志导入到自己搭建的搜索引擎中,从而快速查找

  • 用到一些业界成熟的方案,比如 ES(倒排索引原理) 这种
  • 13
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值