文章目录
一、walk 遍历文件夹内所有文件
使用walk 遍历文件夹,可设置遍历深度,符号链接等。查看 walkdirCargo.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.
流程图 :
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))
}