文章目录

一、walk 遍历文件夹内所有文件

使用walk 遍历文件夹,可设置遍历深度,符号链接等。​​查看 walkdir​​​​Cargo.toml​​文件添加依赖:​​walkdir = "2.3.2"​

use walkdir::WalkDir;

fn main() {
// 直接遍历所有条目
for entry in WalkDir::new("./") {
println!("{}", entry?.path().display());
}

// 遍历所有条目并忽略可能出现的任何错误(跳过正在运行的进程的或无权访问的目录。)
for entry in WalkDir::new("./").into_iter().filter_map(|e| e.ok()) {
println!("{}", entry.path().display());
}
}

遍历输出非​​.jpg​​ 文件

use walkdir::{WalkDir,DirEntry};

fn main() {
WalkDir::new(r"C:\Users\SongpingWang\Desktop\新建文件夹")
.into_iter()
.filter_entry(|e|is_not_hidden(e))
.filter_map(|v|v.ok())
.for_each(|x|println!("{}",x.path().display()));
}


fn is_not_hidden(entry:&DirEntry) ->bool{
entry
.file_name()
.to_str()
.map(|s| !s.ends_with(".jpg"))
.unwrap_or(false)
}

用于异步和递归遍历目录的实用程序
​​​Cargo.toml​​​文件添加依赖:​​async-walkdir = "0.2.0"​

use async_walkdir::WalkDir;
use futures_lite::future::block_on;
use futures_lite::stream::StreamExt;

block_on(async {
let mut entries = WalkDir::new("my_directory");
loop {
match entries.next().await {
Some(Ok(entry)) => println!("file: {}", entry.path().display()),
Some(Err(e)) => {
eprintln!("error: {}", e);
break;
}
None => break,
}
}
});

不要通过名称以​​"."​​开头的目录进行递归:

use async_walkdir::{Filtering, WalkDir};
use futures_lite::future::block_on;
use futures_lite::stream::StreamExt;

block_on(async {
let mut entries = WalkDir::new("my_directory").filter(|entry| async move {
if let Some(true) = entry
.path()
.file_name()
.map(|f| f.to_string_lossy().starts_with('.'))
{
return Filtering::IgnoreDir;
}
Filtering::Continue
});

loop {
match entries.next().await {
Some(Ok(entry)) => println!("file: {}", entry.path().display()),
Some(Err(e)) => {
eprintln!("error: {}", e);
break;
}
None => break,
}
}
});

二、zip 压缩与解压

​Cargo.toml​​​文件添加依赖:
​​​zip = "0.5.12"​​​ #压缩
​​​walkdir = "2.3.2"​​ # 目录使用

use std::fs::File;
use std::io::prelude::*;
use std::path::Path;
use std::str;

use walkdir::{DirEntry,WalkDir};
use zip::write::FileOptions;


fn main() {
let zip_result = compress_dir(Path::new("./"),Path::new("./xxx.zip"));
if let Ok(()) = zip_result{
println!("压缩完成!")
}else {
println!("压缩出错:{:?}",zip_result)
}
}


fn compress_dir(src_dir: &Path, target: &Path) ->std::result::Result<(),Box<dyn std::error::Error>>{
let zipfile = std::fs::File::create(target)?;
let dir = WalkDir::new(src_dir);
zip_dir(&mut dir.into_iter().filter_map(|e|e.ok()),
src_dir.to_str().unwrap(),
zipfile)?;
Ok(())
}

#[warn(dead_code)]
fn compress_file(src_dir: &Path, target: &Path)->std::result::Result<(),Box<dyn std::error::Error>>{
let zipfile = std::fs::File::create(target)?;
let dir = WalkDir::new(src_dir);

let prefix = src_dir.parent().map_or_else(||"/",|p|p.to_str().unwrap());
zip_dir(&mut dir.into_iter().filter_map(|e|e.ok()),prefix,zipfile)?;
Ok(())
}


fn zip_dir<T>(it: &mut dyn Iterator<Item=DirEntry>,
prefix: &str,
writer:T) ->zip::result::ZipResult<()>
where T: Write + Seek{
let mut zip = zip::ZipWriter::new(writer);
let options = FileOptions::default()
.compression_method(zip::CompressionMethod::Bzip2)
.unix_permissions(0o755);
let mut buffer = Vec::new();
for entry in it{
let path = entry.path();
let name = path.strip_prefix(Path::new(prefix)).unwrap();
if path.is_file(){
println!("adding file {:?} as {:?} ...", path, name);
zip.start_file(name.to_string_lossy(),options)?;
let mut f = File::open(path)?;
f.read_to_end(&mut buffer)?;
zip.write_all(&buffer)?;
buffer.clear();
}else if name.as_os_str().len() != 0 {
zip.add_directory(name.to_string_lossy(),options)?;
}
}
zip.finish()?;
Result::Ok(())
}

/// ======================以下代码未测试=====================
///解压
/// test.zip文件解压到d:/test文件夹下
///
fn extract(test: &Path, mut target: &Path) {
let zipfile = std::fs::File::open(&test).unwrap();
let mut zip = zip::ZipArchive::new(zipfile).unwrap();

if !target.exists() {
fs::create_dir_all(target).map_err(|e| {
println!("{}", e);
});
}
for i in 0..zip.len() {
let mut file = zip.by_index(i).unwrap();
println!("Filename: {} {:?}", file.name(), file.sanitized_name());
if file.is_dir() {
println!("file utf8 path {:?}", file.name_raw());//文件名编码,在windows下用winrar压缩的文件夹,中文文夹件会码(发现文件名是用操作系统本地编码编码的,我的电脑就是GBK),本例子中的压缩的文件再解压不会出现乱码
let target = target.join(Path::new(&file.name().replace("\\", "")));
fs::create_dir_all(target).unwrap();
} else {
let file_path = target.join(Path::new(file.name()));
let mut target_file = if !file_path.exists() {
println!("file path {}", file_path.to_str().unwrap());
fs::File::create(file_path).unwrap()
} else {
fs::File::open(file_path).unwrap()
};
copy(&mut file, &mut target_file);
// target_file.write_all(file.read_bytes().into());
}
}
}


fn create_dir(path: &Path) -> Result<(), std::io::Error> {
fs::create_dir_all(path)
}

参考:​​javascript:void(0)​

三、统计文件夹内所有文件所占空间

简单的统计:

  1. 遍历当前文件夹
  2. 判定当前名称是否为文件
    为文件则统计大小
    为文件夹则进入该文件夹,重复1.,2.

流程图 :


Created with Raphaël 2.2.0 开始 遍历当前文件夹 文件/文件夹? 统计文件大小 结束 进入该文件夹 yes no


use std::path::PathBuf;

fn main() -> std::result::Result<(),Box<dyn std::error::Error>>{
let arges = std::env::args().collect::<Vec<String>>();
if arges.len()<2{
panic!("请输入目录名")
}

let space_size = calculate_size(PathBuf::from(arges[1].to_string()))?;
let usage = space_size.file_size(file_size_opts::CONVENTIONAL)?;
println!("space_size:bytes:{},\t normal:{}",space_size,usage);
Ok(())
}


fn calculate_size(path:PathBuf) -> std::io::Result<u64>{
let mut paths = vec![path];
let mut res_size = 0u64;
while let Some(path) = paths.pop(){
let meta = std::fs::symlink_metadata(&path)?;
let file_type = meta.file_type();
if file_type.is_dir(){
let entries = std::fs::read_dir(path)?;
for entry in entries{
paths.push(entry?.path());
}
}
if file_type.is_file(){
res_size += meta.len();
}
}
Ok(res_size)
}

异步实现
​​​toml​​文件

[dependencies]
humansize = "1.1.0"
tokio = { version = "1.5.0", features = ["full"] }
futures = "0.3.14"
use std::path::PathBuf;
use humansize::{file_size_opts,FileSize};
use tokio::fs;
use futures::TryStreamExt;
use futures::stream::FuturesUnordered;
use std::fs::Metadata;


#[tokio::main]
async fn main() -> std::result::Result<(),Box<dyn std::error::Error>>{
let arges = std::env::args().collect::<Vec<String>>();
if arges.len()<2{
panic!("请输入目录名")
}

let space_size = calculate_size(PathBuf::from(arges[1].to_string())).await?;
let usage = space_size.file_size(file_size_opts::CONVENTIONAL)?;
println!("space_size:bytes:{},\t normal:{}",space_size,usage);
Ok(())
}


async fn calculate_size(path:PathBuf) -> std::io::Result<u64>{
let mut file_queue = FuturesUnordered::new();
file_queue.push(file_for_path(path));

let mut res_size = 0u64;
while let Some((path,meta)) = file_queue.try_next().await?{
let file_type = meta.file_type();
if file_type.is_dir(){
let mut entries = fs::read_dir(path).await?;
while let Some(entry) = entries.next_entry().await?{
file_queue.push(file_for_path(entry.path()))
}
}
if file_type.is_file(){
res_size += meta.len();
}
}
Ok(res_size)
}


async fn file_for_path(path:PathBuf) ->std::io::Result<(PathBuf,Metadata)>{
let meta = fs::symlink_metadata(&path).await?;
Ok((path,meta))
}