欢迎加入开源鸿蒙PC社区: https://harmonypc.csdn.net/
欢迎在PC社区平台申请新建项目:https://atomgit.com/OpenHarmonyPCDeveloper
AtomGit 仓库地址:https://atomgit.com/OpenHarmonyPCDeveloper/ohos_rust_cargo

本文讲解鸿蒙 PC 端 Rust 开发环境搭建,鸿蒙基于 musl 库、强制二进制签名,无法直接使用通用 Linux 编译产物。需借助鸿蒙专属包管理器 Harmonybrew,提供两套编译方案:方案一安装 llvm-gcc-compat,零配置开箱即用;方案二仅安装 ohos-sdk,需手动配置 Cargo 链接器,二者都依托 ohos-sdk 完成自动签名编译。

完整的过程可以参考一下:

【OpenHarmony 鸿蒙 PC + CodeArts IDE 实现 Rust开发完整开发环境搭建指南】


一、walkdir 库介绍

作用

walkdir 是 Rust 递归遍历目录的专用库,比标准库 std::fs::read_dir 更强大、易用。

核心能力

  1. 递归遍历文件夹下所有文件+子目录(深度遍历)
  2. 过滤文件/目录、跳过隐藏文件、按后缀筛选(.txt/.json等)
  3. 获取文件元信息:大小、是否文件/文件夹、路径、修改时间
  4. 控制遍历深度,避免无限递归
  5. 自动处理 IO 错误,友好错误处理

适用场景

批量读取目录文件、日志扫描、文件批量处理、项目文件检索、本地文件同步、静态资源遍历。

二、安装

cargo add walkdir

Cargo.toml 自动添加:

[dependencies]
walkdir = "2"

请添加图片描述

三、完整无报错示例代码 main.rs

包含 4 个常用场景:基础遍历、只找指定后缀文件、限制遍历深度、过滤隐藏文件

use walkdir::{DirEntry, WalkDir};
use std::path::Path;

fn main() {
    // 1. 基础递归遍历当前目录所有文件和文件夹
    println!("===== 1. 递归遍历当前目录全部内容 =====");
    walk_all_dir(".");

    // 2. 只查找 .rs 源码文件
    println!("\n===== 2. 筛选所有rs源码文件 =====");
    find_file_by_suffix(".", ".rs");

    // 3. 只遍历2层目录,不深度递归
    println!("\n===== 3. 限制遍历深度最多2级 =====");
    walk_limit_depth(".", 2);

    // 4. 过滤隐藏文件/隐藏文件夹(以.开头)
    println!("\n===== 4. 跳过所有隐藏文件 =====");
    walk_skip_hidden(".");
}

/// 基础递归遍历目录,打印所有条目
fn walk_all_dir(root: &str) {
    // WalkDir::new 创建目录迭代器
    for entry in WalkDir::new(root).into_iter().flatten() {
        print_entry_info(&entry);
    }
}

/// 按后缀筛选文件(只输出普通文件,跳过文件夹)
fn find_file_by_suffix(root: &str, suffix: &str) {
    let walker = WalkDir::new(root).into_iter().flatten();
    for entry in walker {
        // 只匹配普通文件,跳过文件夹
        if entry.file_type().is_file() {
            let path = entry.path();
            if path.extension().and_then(|s| s.to_str()) == Some(suffix.strip_prefix('.').unwrap()) {
                println!("匹配文件: {}", path.display());
            }
        }
    }
}

/// 限制最大遍历深度
fn walk_limit_depth(root: &str, max_depth: usize) {
    let walker = WalkDir::new(root)
        .max_depth(max_depth) // 限制层级
        .into_iter()
        .flatten();
    for entry in walker {
        print_entry_info(&entry);
    }
}

/// 过滤隐藏文件/隐藏目录(unix .开头文件)
fn walk_skip_hidden(root: &str) {
    let walker = WalkDir::new(root)
        .into_iter()
        .filter_map(|e| e.ok()) // 忽略IO错误
        .filter(|e| {
            // 文件名不以 . 开头
            !e.file_name()
                .to_str()
                .map(|s| s.starts_with('.'))
                .unwrap_or(false)
        });

    for entry in walker {
        print_entry_info(&entry);
    }
}

/// 打印一条目录条目的基础信息
fn print_entry_info(entry: &DirEntry) {
    let path = entry.path();
    let meta = entry.metadata().unwrap();
    let kind = if meta.is_dir() { "文件夹" } else { "文件" };
    println!(
        "[{}] 路径: {} | 大小: {} bytes",
        kind,
        path.display(),
        meta.len()
    );
}

请添加图片描述

一、库简单回顾

walkdir 是 Rust 递归遍历文件夹的第三方库,对比标准库 std::fs::read_dir,它原生支持递归、深度限制、过滤、错误自动处理,是批量处理本地文件的首选工具。

二、头部导入

use walkdir::{DirEntry, WalkDir};
use std::path::Path;
  1. WalkDir:目录遍历核心迭代器,用来开启文件夹扫描
  2. DirEntry:遍历过程中每一个文件/文件夹的封装对象,包含路径、文件类型、元数据、深度等信息
  3. std::path::Path:标准库路径类型,统一处理跨系统文件路径

三、入口 main 函数

fn main() {
    // 1. 基础递归遍历当前目录所有文件和文件夹
    println!("===== 1. 递归遍历当前目录全部内容 =====");
    walk_all_dir(".");

    // 2. 只查找 .rs 源码文件
    println!("\n===== 2. 筛选所有rs源码文件 =====");
    find_file_by_suffix(".", ".rs");

    // 3. 只遍历2层目录,不深度递归
    println!("\n===== 3. 限制遍历深度最多2级 =====");
    walk_limit_depth(".", 2);

    // 4. 过滤隐藏文件/隐藏文件夹(以.开头)
    println!("\n===== 4. 跳过所有隐藏文件 =====");
    walk_skip_hidden(".");
}

分4个场景演示最常用4种遍历逻辑:

  1. 完整递归扫描全部文件目录
  2. 根据文件后缀筛选指定类型文件
  3. 限制递归层级,不无限下钻子文件夹
  4. 过滤系统隐藏文件(Linux/Mac 以 . 开头的文件,如 .git.env

四、函数1:walk_all_dir 基础全量递归遍历

fn walk_all_dir(root: &str) {
    // WalkDir::new 创建目录迭代器
    for entry in WalkDir::new(root).into_iter().flatten() {
        print_entry_info(&entry);
    }
}
  1. WalkDir::new(root):传入根目录字符串(. 代表当前项目目录),生成递归扫描器
  2. .into_iter():转为迭代器,逐个产出目录条目
  3. .flatten()WalkDir 迭代器产出 Result<DirEntry, WalkDirError>,flatten 自动丢弃IO错误,只保留正常读取到的文件;等价于 filter_map(|res| res.ok())
  4. 循环遍历每一个 DirEntry,调用统一打印函数输出信息

适用场景:全盘扫描项目、读取目录下所有资源文件

五、函数2:find_file_by_suffix 按后缀筛选文件

fn find_file_by_suffix(root: &str, suffix: &str) {
    let walker = WalkDir::new(root).into_iter().flatten();
    for entry in walker {
        // 只匹配普通文件,跳过文件夹
        if entry.file_type().is_file() {
            let path = entry.path();
            if path.extension().and_then(|s| s.to_str()) == Some(suffix.strip_prefix('.').unwrap()) {
                println!("匹配文件: {}", path.display());
            }
        }
    }
}

逐行拆解逻辑

  1. entry.file_type().is_file()
    判断当前条目是否为普通文件,过滤掉文件夹、软链接,只保留文件
  2. path.extension() 获取文件后缀 OsStr(例如 main.rs 后缀是 rs
  3. .and_then(|s| s.to_str()) 将后缀转为字符串,处理无后缀文件的空值
  4. suffix.strip_prefix('.').unwrap()
    传入参数是 .rs,去掉开头的 .,拿到纯后缀 rs 用于对比
  5. path.display():安全打印路径,自动处理 Windows / Linux 不同路径分隔符

调用示例 find_file_by_suffix(".", ".rs"):遍历当前目录,只打印所有 Rust 源码文件

六、函数3:walk_limit_depth 限制递归深度

fn walk_limit_depth(root: &str, max_depth: usize) {
    let walker = WalkDir::new(root)
        .max_depth(max_depth) // 限制层级
        .into_iter()
        .flatten();
    for entry in walker {
        print_entry_info(&entry);
    }
}

核心方法:.max_depth(数字)

  • 根目录深度为0,一级子文件夹深度1,二级深度2
  • 示例传参 max_depth=2:最多扫描两层,不会读取三级及更深的子文件夹
    用途:防止遍历超大嵌套目录、只需要浅层目录数据,提升扫描速度

补充配套API:

  • .min_depth(n):只遍历大于等于n层的文件,跳过浅层目录
  • .follow_links(true):跟随软链接(默认关闭,避免循环链接死递归)

七、函数4:walk_skip_hidden 过滤隐藏文件

fn walk_skip_hidden(root: &str) {
    let walker = WalkDir::new(root)
        .into_iter()
        .filter_map(|e| e.ok()) // 忽略IO错误
        .filter(|e| {
            // 文件名不以 . 开头
            !e.file_name()
                .to_str()
                .map(|s| s.starts_with('.'))
                .unwrap_or(false)
        });

    for entry in walker {
        print_entry_info(&entry);
    }
}
  1. .filter_map(|e| e.ok()):手动处理Result,读取失败的目录直接丢弃
  2. e.file_name():获取当前条目文件名(不含完整路径)
  3. .map(|s| s.starts_with('.')):判断文件名是否以 . 开头(隐藏文件标记)
  4. ! 取反,只保留非隐藏文件和文件夹
    作用:遍历项目时忽略 .git.vscode.env 等隐藏目录文件

八、公共工具函数 print_entry_info 统一打印文件信息

fn print_entry_info(entry: &DirEntry) {
    let path = entry.path();
    let meta = entry.metadata().unwrap();
    let kind = if meta.is_dir() { "文件夹" } else { "文件" };
    println!(
        "[{}] 路径: {} | 大小: {} bytes",
        kind,
        path.display(),
        meta.len()
    );
}
  1. entry.path():获取完整路径对象
  2. entry.metadata():读取文件元数据(大小、类型、修改时间、权限等)
  3. meta.is_dir():区分文件夹 / 文件
  4. meta.len():文件字节大小,文件夹统一返回0
  5. path.display():跨平台友好打印路径,不会出现乱码

九、DirEntry 高频内置方法汇总

entry.path()            // &Path 完整路径
entry.file_name()       // OsStr 纯文件名
entry.depth()           // usize 当前目录层级深度
entry.file_type()       // 判断 文件/文件夹/软链接
entry.metadata()        // 文件元数据(大小、修改时间)
entry.into_path()       // 转为 Owned PathBuf

十、整体业务使用场景

  1. 批量读取日志文件夹下所有 .log 文件解析日志
  2. 项目静态资源批量复制、压缩、重命名
  3. 文件查重、统计目录总占用空间
  4. CLI工具扫描指定格式配置文件
  5. 过滤隐藏目录,只处理业务代码文件

四、代码逐段详解

1. 导入

use walkdir::{DirEntry, WalkDir};
use std::path::Path;
  • WalkDir:目录遍历生成器,迭代器主体
  • DirEntry:每一条遍历结果,包含路径、文件类型、元数据等信息

2. 基础遍历 WalkDir::new(root)

WalkDir::new(".")

传入根目录,生成递归迭代器;
.into_iter().flatten():自动处理 IO 错误,忽略读取失败目录(等价于 filter_map(|e| e.ok())

3. DirEntry 常用方法

entry.path()          // &Path 文件完整路径
entry.file_name()     // OsStr 文件名/文件夹名
entry.file_type()     // 判断是文件/目录/软链接
entry.metadata()      // 获取文件元数据(大小、修改时间等)
entry.depth()         // 当前相对根目录的层级深度

4. 关键配置 API

WalkDir::new(path)
    .max_depth(n)       // 限制最大递归层级
    .follow_links(true) // 跟随软链接(默认false,不跟随防止循环)
    .min_depth(n)       // 最小遍历层级,跳过浅层目录

5. 文件后缀筛选逻辑

path.extension().and_then(|s| s.to_str()) == Some("rs")

获取文件后缀名字符串,匹配目标后缀,仅打印普通文件,跳过文件夹。

6. 跳过隐藏文件

过滤文件名以 . 开头的条目(Linux/Mac 隐藏文件,如 .git.env

五、极简高频片段(可单独复制)

批量获取当前目录所有txt文件路径

use walkdir::WalkDir;

fn get_all_txt() -> Vec<String> {
    let mut list = Vec::new();
    for entry in WalkDir::new(".").flatten() {
        if entry.file_type().is_file() && entry.path().extension().unwrap_or_default() == "txt" {
            list.push(entry.path().to_str().unwrap().to_string());
        }
    }
    list
}

获取目录下所有文件总大小

use walkdir::WalkDir;

fn calc_dir_size(root: &str) -> u64 {
    WalkDir::new(root)
        .flatten()
        .filter(|e| e.file_type().is_file())
        .map(|e| e.metadata().unwrap().len())
        .sum()
}

更多推荐