一、文件查找并删除
扫描指定⽬录,并找到名称中包含指定字符的所有普通⽂件(不包含⽬录),并且后续询问⽤⼾是否 要删除该⽂件
一个主要的操作就是需要扫描指定目录(递归)
递归函数
- 首先判断是否是目录,若不是,直接返回
- 若是,则列出当前目录的文件名,放到
files
数组中 - 如果
files
是空的,或者files
数组长度为0
,代表没有文件,则直接返回 - 循环遍历
files
数组- 若此时遍历到的文件是普通文件
- 调用删除文件方法
doDelete
- 调用删除文件方法
- 若磁石遍历到的仍是目录
- 继续递归
- 若此时遍历到的文件是普通文件
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);
}
}
}
}
删除函数
- 文件名中不包含关键字,则直接返回
- 若包含,则提示用户,是否进行删除
- 用户输入
Y/N
进行选择 - 若输入为
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);
}
}
二、文件复制
进⾏普通⽂件的复制
把一个文件里面的每个字节都读出来,再写入另一个文件中
- 输入源文件路径,并实例出一个
srcFile
对象 - 判断这个对象是否是一个文件,若不是,则返回
- 若是,则继续输入目标文件的路径
- 以这个路径实例化出一个
dextFile
文件 - 得到这个文件所在处的父目录,并判断其是否是一个目录
- 若是,则开始执行复制的过程
- 通过
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(倒排索引原理) 这种