diskusage
diskusage
是 显示磁盘使用情况的工具。同时支持(Linux、macOS 和 Windows)三大系统。
虽然说现在有很多的磁盘使用情况的工具,diskusage
还是有他的独特之处,他使用的是go
语言进行编写,代码量非常的小,非常适合我们的go
语言的初学着,等下我们也会对主要的代码进行分析,清楚的知道这款工具的逻辑。
安装
diskusage
的安装也比较简单了,使用传统的go install
就能轻松的把diskusage
安装到本地。
go install github.com/chenquan/diskusage@latest
使用
先看看使用帮助,来显示出diskusage
所支持的命令和diskusage
的功能。diskusage -h
$ diskusage -h A tool for showing disk usage. Usage: diskusage [flags]Flags: -a, --all display all directories, otherwise only display folders whose usage size is not 0 -c, --color string set color output mode. optional: auto, always, ignore (default "auto") -d, --depth int shows the depth of the tree directory structure (default 1) --dir string dir path (default "./") -f, --filter string regular expression filter (default ".+") -h, --help help for diskusage -t, --type strings only count certain types of files (default all) -u, --unit string displayed units. optional: B(Bytes), K(KB), M(MB), G(GB), T(TB) (default "M")
最常见的一个功能就是列出当前目录的占用情况,经常我们在使用 linux的过程中,会产生一些文件,使得我们的磁盘爆满,但是我们又不知道占用最大空间的文件它在哪里,可以使用diskusage -a
的命令来显示目录的占用情况。
diskusage -a
显示当前目录的情况如下:
Total: 3114.888M /root --------------------------------- 1692.0M 54.3% ┌─ snap 1284.5M 41.2% ├─ .cache 100.2M 3.2% ├─ .EasyOCR 31.0M 1.0% ├─ go 4.3M 0.1% ├─ flutter-webrtc-demo 2.1M 0.1% ├─ .launchpadlib 0.4M 0.0% ├─ 1yw32lok3j51yw32lok3j5.jpg 0.2M 0.0% ├─ 1yw32lok3j51yw32lok3j5-1.jpg 54.1K 0.0% ├─ 4f70c06988d732947b62c18501a876a8-1.jpeg 43.6K 0.0% ├─ 4f70c06988d732947b62c18501a876a8.jpeg 22.5K 0.0% ├─ Dingtalk_20220804094819.jpg 14.7K 0.0% ├─ .viminfo 3.7K 0.0% ├─ .bashrc 0.6K 0.0% ├─ .bash_history 0.5K 0.0% ├─ scene.py 0.2K 0.0% ├─ .python_history 0.2K 0.0% ├─ .profile 0.1K 0.0% ├─ .config 78.0B 0.0% ├─ .flutter 0.0B 0.0% ├─ .jina 0.0B 0.0% └─ .sudo_as_admin_successful
这个就非常清楚的展示了目录的情况,当前目录大小3114.888M,snap
目录占了1692.0M 占了 54.3%,目录的情况一目了然,还怕找不到相关的文件吗?
代码分析
diskusage
的文件结构也比较简单,最重要的文件为stat.go
,有几个函数比较关键,接下来一个一个分析下,也比较简单,相当于教我们怎么 统计文件夹的情况。
主函数在这里,看起来逻辑也挺正常的,先算总的文件大小,在一个一个的去遍历:
func Stat(cmd *cobra.Command, _ []string) error { flags := cmd.Flags() dir, err := flags.GetString("dir") if err != nil { return err } depth, err := flags.GetInt("depth") if err != nil { return err } unit, err := getUnit(flags) if err != nil { return err } dir, err = filepath.Abs(dir) if err != nil { return err } types, err := flags.GetStringSlice("type") if err != nil { return err } typeMap := make(map[string]struct{}, len(types)) for _, s := range types { typeMap["."+s] = struct{}{} } filter, err := flags.GetString("filter") if err != nil { return err } compile, err := regexp.Compile(filter) if err != nil { return err } all, err := flags.GetBool("all") if err != nil { return err } err = handleColor(flags) if err != nil { return err } go func() { defer close(errChan) files, err := find(dir, func(info fs.FileInfo) bool { if info.IsDir() { return true } name := info.Name() ext := filepath.Ext(name) _, ok := typeMap[ext] typeB := ok || len(types) == 0 filterB := compile.MatchString(name) return typeB && filterB }) if err != nil { errChan <- err return } totalSize := int64(0) for _, f := range files { totalSize += f.size } val, reduceUnit := getReduce(unit, totalSize) header := fmt.Sprintf("Total: %0.3f%s\t%s", val, reduceUnit, color.HiGreenString(dir)) colorPrintln(header) colorPrintln(strings.Repeat("-", len(header)+2)) l := list.NewWriter() l.SetStyle(list.StyleConnectedLight) infoFiles := buildInfoFile(l, files, 0, depth, unit, totalSize, all) maxLen := 0 for _, info := range infoFiles { if maxLen < len(info.str) { maxLen = len(info.str) } } printTree(l.Render(), infoFiles, maxLen) errChan <- nil }() if <-errChan != nil { return err } return nil}
文件大小格式化:
func getReduce(unit string, n int64) (float64, string) { reduce := 0 switch unit { case "B": reduce = 0 case "K": reduce = 1 case "M": reduce = 2 case "G": reduce = 3 case "T": reduce = 4 } for { if reduce <= 0 { break } if int(float64(n)/float64(units[reduce])*10) > 0 { break } reduce-- } return float64(n) / float64(units[reduce]), unitStrings[reduce]}
查找文件:
func find(dir string, filter func(info fs.FileInfo) bool) ([]file, error) { if !sysFilter(dir) { return nil, nil } dirEntries, err := os.ReadDir(dir) if err != nil { if pathError, ok := err.(*fs.PathError); ok { // currently only supports Windows if accessDeniedSyscall(pathError.Err) { return nil, errorAccessDenied } } return nil, err } var wg = sync.WaitGroup{} fileChan := make(chan file, len(dirEntries)) for _, entry := range dirEntries { entry := entry fileInfo, err := entry.Info() if err != nil { return nil, err } if !filter(fileInfo) { continue } if !entry.IsDir() { fileChan <- file{ name: entry.Name(), size: fileInfo.Size(), } continue } wg.Add(1) do := func() { defer wg.Done() subFiles, err := find(path.Join(dir, entry.Name()), filter) if err != nil { if accessDenied(err) { return } errChan <- err } totalSize := int64(0) for _, subFile := range subFiles { totalSize += subFile.size } fileChan <- file{ sub: subFiles, name: entry.Name(), isDir: true, size: totalSize, } } w.Run(do) } wg.Wait() close(fileChan) files := make([]file, 0, len(dirEntries)) for f := range fileChan { files = append(files, f) } sort.Slice(files, func(i, j int) bool { return files[i].size > files[j].size }) return files, nil}
递归遍历文件信息:
func buildInfoFile(l list.Writer, files []file, n, depth int, unit string, totalSize int64, all bool) []infoFile { if n == depth { return nil } var infoFiles []infoFile for _, f := range files { if f.isDir && f.size == 0 && !all { continue } val, reduceUnit := getReduce(unit, f.size) infoFiles = append(infoFiles, infoFile{ size: val, uint: reduceUnit, usageRate: float64(f.size) / float64(totalSize) * 100, str: fmt.Sprintf("%0.1f", val), isDir: f.isDir, }) name := f.name if f.isDir { name = color.HiGreenString(name) } l.AppendItem(name) if f.isDir { l.Indent() subUsageSizes := buildInfoFile(l, f.sub, n+1, depth, unit, totalSize, all) infoFiles = append(infoFiles, subUsageSizes...) l.UnIndent() } } return infoFiles}
把结果显示出来:
func printTree(content string, infoFiles []infoFile, maxLen int) { size := len(infoFiles) format := " %" + strconv.Itoa(maxLen) + ".1f%s %5.1f%%" for i, line := range strings.Split(content, "\n") { if i >= size { continue } info := infoFiles[i] str := fmt.Sprintf(format, info.size, info.uint, info.usageRate) if info.isDir { str = color.HiRedString(str) } colorPrintln(str, line) }
推荐本站淘宝优惠价购买喜欢的宝贝:
本文链接:https://hqyman.cn/post/5981.html 非本站原创文章欢迎转载,原创文章需保留本站地址!
打赏
微信支付宝扫一扫,打赏作者吧~
休息一下~~