import (
"fmt"
"io/fs"
"log"
"os"
"path/filepath"
"sync"
)
// WalkDir 外部调用的遍历目录统计信息的方法
func WalkDir(dirs ...string) string {
// 保证至少有一个目录需要统计遍历
// 默认当前目录
if len(dirs)==0{
dirs=[]string{"."}
}
// 初始化变量,channel用于完成Size的传递,WaitGroup用于等待调度
fileSizeCh:=make(chan int64,1)
wg:=&sync.WaitGroup{}
// 启动多个Goroutine统计信息,取决于len(dirs)
for _,dir:=range dirs{
wg.Add(1)
// 并发的编历统计每个目录的信息
go walkDir(dir,fileSizeCh,wg)
}
// 启动累计运算的Goroutine
// 1.用户关闭fileSizeCh
go func(wg *sync.WaitGroup) {
// 等待统计工作完成
wg.Wait()
// 关闭fileSizeCh
close(fileSizeCh)
}(wg)
// 2,range的方式从fileSizeCh中获取文件大小
// 3. 统计结果,使用channel传递出来
fileNumCh:=make(chan int64,1)
sizeTotalCh:=make(chan int64,1)
go func(fileSizeCh <-chan int64,fileNumCh,sizeTotalCh chan<- int64) {
// 统计文件数,和文件整体大小
var fileNum,sizeToTal int64
// 遍历全部的filesizeCh元素,统计文件数量和大小,直到channel被关闭
for filesize:=range fileSizeCh{
// 累计文件数,和统计文件整体大小
fileNum++
sizeToTal+=filesize
}
// 将统计结果发送到对应的channel中
fileNumCh<-fileNum
sizeTotalCh<-sizeToTal
}(fileSizeCh,fileNumCh,sizeTotalCh)
// 整理返回值
// size 的单位是Byte
// 需要的单位是 MB
result:=fmt.Sprintf("%d files %.2f MB\n",<-fileNumCh,float64(<-sizeTotalCh)/1e6)
return result
}
// 遍历并统计某个目录的信息
// 核心实现函数,完成递归,统计等
func walkDir(dir string,fileSizeCh chan<-int64,wg *sync.WaitGroup) {
// 一:wg的计数器减少
defer wg.Done()
// 二:读取dir下的全部文件信息,并遍历
for _,fileinfo:=range fileInfos(dir){
// 三:根据dir下的文件信息
if fileinfo.IsDir(){
// 1.如果目录,递归获取信息
// 子目录地址
subDir:=filepath.Join(dir,fileinfo.Name())
// 递归调用,阳是并发的,也需要wg统计
wg.Add(1)
go walkDir(subDir,fileSizeCh,wg)
}else{
// 2.如果不是,就是文件,统计文件大小,放入channel
fileSizeCh<-fileinfo.Size()
}
}
}
// 获取某个目录下的文件信息列表
func fileInfos(dir string)[]fs.FileInfo {
// 1.读取目录的全部文件
entries,err:=os.ReadDir(dir)
if err!=nil{
log.Println("WalkDir error:",err)
return []fs.FileInfo{}
}
// 2.如获取文件的文件信息
// DirEntry to FileInfo
infos:=make([]fs.FileInfo,0,len(entries))
for _,entry:=range entries{
// 如果获取文件信息无错误,存储到Infos中
if info,err:=entry.Info();err==nil{
infos=append(infos,info)
}
}
// 3.返回
return infos
}
GO并发统计文件大小
lisus20072026-03-13 16:53
相关推荐
旺仔不是程序员几秒前
判断存在用 LIMIT 1:PostgreSQL 五种 count 计数方式与 NULL 语义旺仔不是程序员2 分钟前
IN 操作规范:PostgreSQL 元素数量、EXISTS 替代与 = ANY 写法小白学大数据6 分钟前
Python 项目实战:用 Flask 构建生产级 MySQL 增删改查 REST API晚安日记wanna10 分钟前
一条 SMEMBERS 干瘫 Redis 节点:单线程的真正边界在哪码事漫谈10 分钟前
32 位事务号的宿命:金仓 V9 如何用 64 位 XID 破解 PG 三十年顽疾码事漫谈11 分钟前
在 Kubernetes 上管好数据库:金仓 KES-Operator 正式落地小蒜学长16 分钟前
基于SpringBoot+Vue的游戏论坛系统的设计与实现(代码+数据库+LW)Nil20819 分钟前
leetcode 20有效的括号SimonKing22 分钟前
文档杂乱怎么查找:用 Papra 搭一个极简文档管理系统掘金者阿豪25 分钟前
金仓、MySQL、PostgreSQL 用什么管理工具?DBeaver、Navicat、KStudio 我都试了一遍