rust递归遍历磁盘目录及文件

Std库实现

rust 复制代码
//遍历dir目录,找出修改日期距离当前超过age天的文件名称,存入file_list中
fn visit_dir(dir: &Path, file_list: &mut Vec<String>, age: u64) -> io::Result<()> {
    if dir.is_dir() {
        for entry in fs::read_dir(dir)? {
            let entry = entry?;
            let path = entry.path();
            if path.is_dir() {
                visit_dir(&path, file_list, age)?;
            } else {
                let file_matedata = fs::metadata(entry.path()).unwrap();
                let modify_time = file_matedata.modified()?;
                if modify_time + Duration::from_secs(age * 24 * 60 * 60) < SystemTime::now(){
                    file_list.push(entry.path().to_str().unwrap().to_string());
                }
            }
        }
    }
    Ok(())
}

//遍历dir目录,找出空目录(内部无文件,无目录)
fn get_empty_dir(dir: &Path, dir_list: &mut Vec<String>) -> io::Result<()>{
    if !dir.is_dir() {
        return Ok(());
    }
    let read_dir = fs::read_dir(dir)?;
    let cnt = read_dir.count();
    if cnt == 0 {
        dir_list.push(dir.to_str().unwrap().to_owned());
        return Ok(());
    }

    let read_dir = fs::read_dir(dir)?;
    for entry in read_dir{
        let entry = entry?;
        let path = entry.path();
        if path.is_dir() {
            get_empty_dir(path.as_path(), dir_list)?;
        }
    }
    Ok(())
}

上述函数实现比较直接,需要注意fs::read_dir()函数返回值后面的?宏,从read_dir返回值中提取结果。如visit_dir、get_empty_dir函数定义返回值不是io::Result类型,使用?宏,会报错。因为?宏还涉及错误传播,需要io::Result参与。

Tokio实现

Rust的异步递归函数实现比较繁琐,为了简化,导入如下Crate:

复制代码
async-recursion = "1.0.5"
rust 复制代码
use async_recursion::async_recursion;
#[async_recursion]
async fn visit_dir_async(dir: &Path, file_list: &mut Vec<String>, age: u64) {
    if dir.is_dir() {
        //for entry in tokio::fs::read_dir(dir).flat_map().await? {
        let mut entries = tokio::fs::read_dir(dir).await.unwrap();
        while let Some(entry) = entries.next_entry().await.unwrap() {
            let path = entry.path();
            if path.is_dir() {
                visit_dir_async(&path, file_list, age).await;
            } else {
                let file_matedata = tokio::fs::metadata(entry.path()).await.unwrap();
                let modify_time = file_matedata.modified().unwrap();
                if modify_time + Duration::from_secs(age * 24 * 60 * 60) < SystemTime::now(){
                    file_list.push(entry.path().to_str().unwrap().to_string());
                }
            }
        }
    }
    ()
}

#[async_recursion]
async fn get_empty_dir_async(dir: &Path, dir_list: &mut Vec<String>) {
    println!("check path:{}", dir.to_str().unwrap());
    if !dir.is_dir() {
        return;
    }
    let mut read_dir = tokio::fs::read_dir(dir).await.unwrap();
    if let None = read_dir.next_entry().await.unwrap(){
        println!("find none path");
        dir_list.push(dir.to_str().unwrap().to_owned());
        return;
    }
    let mut read_dir = tokio::fs::read_dir(dir).await.unwrap();
    while let Some(entry) = read_dir.next_entry().await.unwrap(){
        let path = entry.path();
        if path.is_dir() {
            get_empty_dir_async(path.as_path(), dir_list).await;
        }
    }
}

调用

rust 复制代码
use tokio::io::{self, BufReader, AsyncBufReadExt, BufWriter, AsyncWriteExt};
use tokio::fs::{File, try_exists, remove_file, read_to_string, copy, read_dir};
use std::path::{PathBuf};

use std::fs::File as fsFile;
use std::fs;
use std::path::Path;
use std::fs::{DirEntry};
use std::time::{Duration, SystemTime};


#[tokio::main]
async fn main() -> io::Result<()> {
    let source_dir = "E:\\xxxxxx\\Log\\";
    //获取目录中的全部文件
    let mut file_list: Vec<String> = Vec::new();
    let path = Path::new(source_dir);
    visit_dir(path, &mut file_list, 30)?;
    for file in file_list{
        println!("{}", file);
    }

    let mut empty_file_list: Vec<String> = Vec::new();
    let path = Path::new(source_dir);
    get_empty_dir(path, &mut empty_file_list)?;
    for dir in empty_file_list{
        println!("{}", dir);
    }

    println!("====tokio==================================");
    let source_dir = "E:\\xxxxxx\\Log\\";
    //获取目录中的全部文件
    let mut file_list: Vec<String> = Vec::new();
    let path = Path::new(source_dir);
    visit_dir_async(path, &mut file_list, 30).await;
    for dir in file_list{
        println!("tokio {}", dir);
    }
    println!("====tokio==================================");
    let mut empty_file_list: Vec<String> = Vec::new();
    get_empty_dir_async(path, &mut empty_file_list).await;
    for dir in empty_file_list{
        println!("tokio {}", dir);
    }
    Ok(())
}
相关推荐
熊猫钓鱼>_>2 分钟前
Kotlin Multiplatform for OpenHarmony 实战:kotlinx-coroutines 结构化并发适配
开发语言·kotlin·agent·harmonyos·openharmony·适配·华为云码道
bigcarp7 分钟前
Frida-dexdump 绕过app的Root检测
linux·运维·服务器
ggaofeng7 分钟前
linux中的绿色版内存mysql
linux·运维·mysql
沫璃染墨14 分钟前
《Qt从零入门系列(十四):QThread多线程详解——从线程创建到客户端阻塞处理》
开发语言·c++·笔记·qt·ui·交互·线程
草莓熊Lotso16 分钟前
【C++ 基于微服务的即时通讯系统】Elasticsearch 从安装到 C++ 客户端二次封装全落地
linux·网络·数据库·c++·elasticsearch·微服务
hixiong12327 分钟前
C# 使用 ZXingCpp.Angle 进行条码、二维码识别
开发语言·c#·扫码
云和数据.ChenGuang29 分钟前
AI 工程师相关就业岗位(细分,偏工程落地,由底层到上层)
服务器·开发语言·人工智能·python
LiaoWL12334 分钟前
从零开始学 Linux(二):Shell 脚本入门与文本处理实战
linux·运维·服务器
爱读书的小胖39 分钟前
Codewars:Last digit of a large number(C)解题分析
c语言·开发语言·r语言
.道阻且长.1 小时前
Linux软件包管理器
linux·运维·ubuntu·职场和发展·centos