先来看看效果图



速度非常快,只需要0.55秒, 就可以扫描整个C盘

项目使用的了Go语言+React,
Go的框架是Walis
https://wails.io/zh-Hans/docs/introduction/
图表库用的是
项目的源码在
https://github.com/liu-wh/DiskStatistics
这里贴一下核心的代码, 就是如何实现递归扫描整个C盘的
package main
import (
"context"
"fmt"
"github.com/panjf2000/ants/v2"
"log"
"os"
"path/filepath"
"sync"
"time"
"github.com/shirou/gopsutil/v3/disk"
)
var (
RootPath string
)
type DiskTree struct {
Name string `json:"name"`
Children []any `json:"children"`
}
type DirNode struct {
Children []any `json:"children"`
Name string `json:"name"`
}
type Node struct {
Name string `json:"name"`
Value int `json:"value"`
}
func scanDirTwo(path string, wait *sync.WaitGroup, node *DirNode, pool *ants.Pool) {
//读取目录下的文件信息
dirAry, err := os.ReadDir(path)
if err != nil {
return
}
for _, e := range dirAry {
//是目录 递归调用,并且创建一个硬盘树节点
if e.IsDir() {
wait.Add(1)
childNode := &DirNode{Name: e.Name(), Children: make([]any, 0, 100)}
node.Children = append(node.Children, childNode)
_ = pool.Submit(
func() {
scanDirTwo(filepath.Join(path, e.Name()), wait, childNode, pool)
wait.Done()
})
} else {
//是文件, 存入到硬盘树节点
info, err := e.Info()
if err != nil {
continue
}
childNode := &Node{Name: e.Name(), Value: int(info.Size())}
node.Children = append(node.Children, childNode)
}
}
}
// App struct
type App struct {
ctx context.Context
}
func (a *App) DiskTreeMapStatistics() DiskTree {
//初始化线程池
pool, _ := ants.NewPool(1000)
defer pool.Release()
start := time.Now()
//初始化一颗硬盘树
diskTree := DiskTree{Name: RootPath}
paths, _ := os.ReadDir(RootPath)
diskTree.Children = make([]any, 0, len(paths))
//获取根目录的剩余空间
d, _ := disk.Usage(RootPath)
diskTree.Children = append(diskTree.Children, Node{Name: "可用空间", Value: int(d.Free)})
var (
loopWg sync.WaitGroup
info os.FileInfo
err error
)
//开始扫描根目录下的目录
for _, p := range paths {
var wait sync.WaitGroup
loopWg.Add(1)
wait.Add(1)
if info, err = p.Info(); err != nil {
continue
}
//如果是目录, 使用另外一个函数开始扫描
if p.IsDir() {
node := &DirNode{Name: p.Name(), Children: make([]any, 0, 50)}
diskTree.Children = append(diskTree.Children, node)
_ = pool.Submit(func() {
scanDirTwo(filepath.Join(RootPath, p.Name()), &wait, node, pool)
wait.Done()
})
} else {
//不是目录的话, 把文件信息存到硬盘树
wait.Done()
node := &Node{Name: p.Name(), Value: int(info.Size())}
diskTree.Children = append(diskTree.Children, node)
}
wait.Wait()
loopWg.Done()
}
loopWg.Wait()
log.Printf("扫描结束, 用时%s秒\n", fmt.Sprintf("%0.2f", time.Since(start).Seconds()))
return diskTree
}
// StartSan 前端点击扫描, 就会调用这个函数
func (a *App) StartSan() DiskTree {
return a.DiskTreeMapStatistics()
}
发表回复