我试着用Golang学习目录的磁盘使用情况,但下面的应用程序计算不正确.我不想用filepath.Walk美元.我try 了os.Stat(),但没有得到实际的目录大小.我分享了下面的相关代码语句,正确的目录信息和APP的结果.

const (
    B  = 1
    KB = 1024 * B
    MB = 1024 * KB
    GB = 1024 * MB
)

type DiskStatus struct {
    All  uint64
    Free uint64
    Used uint64
}

func DiskUsage(path string) (ds DiskStatus) {
    fs := syscall.Statfs_t{}
    err := syscall.Statfs(path, &fs)
    if err != nil {
        return
    }
    ds.All = fs.Blocks * uint64(fs.Bsize)
    ds.Free = fs.Bfree * uint64(fs.Bsize)
    ds.Used = ds.All - ds.Free
    fmt.Println(path, ds.Used)
    return ds
}

func GetDir(destination_directory string) *[]model.Directory {
    var dir []model.Directory
    items, err := ioutil.ReadDir(destination_directory)

    if err != nil {
        log.Fatalln(err)
    }

    for _, item := range items {
        size := DiskUsage(destination_directory+item.Name()).Used / GB
        item := model.Directory{Path: item.Name(), TotalSize: size}
        dir = append(dir, item)
    }
    return &dir
}

正确的目录信息:

$du -sh *
8.0K containers
2.0G testfolder
3.2M workspace

按应用程序统计的结果:

containers --> 90
testfolder --> 90
workspace --> 90

推荐答案

我相信您误用了syscall.Statfs function:它返回file system statistics,而不是单个目录或文件的大小.因此,您看到的输出不是单个目录的大小,而是这些目录所在的文件系统的总体磁盘使用率.

如果您不想使用filepath.Walk(这实际上是通过递归遍历所有文件来计算目录大小的好方法),您可以使用your own recursive function.

package main

import (
    "os"
    "log"
    "fmt"
)

const (
    B  = 1
    KB = 1024 * B
    MB = 1024 * KB
    GB = 1024 * MB
)

func DirSize(path string) (int64, error) {
    var size int64
    entries, err := os.ReadDir(path)
    if err != nil {
        return size, err
    }
    for _, entry := range entries {
        if entry.IsDir() {
            subDirSize, err := DirSize(path + "/" + entry.Name())
            if err != nil {
                log.Printf("failed to calculate size of directory %s: %v\n", entry.Name(), err)
                continue
            }
            size += subDirSize
        } else {
            fileInfo, err := entry.Info()
            if err != nil {
                log.Printf("failed to get info of file %s: %v\n", entry.Name(), err)
                continue
            }
            size += fileInfo.Size()
        }
    }
    return size, nil
}

func main() {
    dirs := []string{"./containers", "./testfolder", "./workspace"}

    for _, dir := range dirs {
        size, err := DirSize(dir)
        if err != nil {
            log.Printf("failed to calculate size of directory %s: %v\n", dir, err)
            continue
        }
        fmt.Printf("%s --> %.2f GB\n", dir, float64(size)/float64(GB))
    }
}

That would go through each directory and file under the given directory and sum up the sizes.
If the entry is a directory, it will recursively calculate the size of the directory.
Although... this code will not handle symbolic links or other special files.


The other option is for the DirSize function uses filepath.Walk to traverse all files under the specified directory, including subdirectories.
The filepath.Walk function takes two arguments: the root directory and a function that will be called for each file or directory in the tree rooted at the root.

Here, for each file it encounters, it adds the size of the file to the total size (ignoring directories).
Since filepath.Walk automatically handles recursive traversal for you, it is generally simpler and more straightforward than manually writing the recursive function.
(playground)

package main

import (
    "os"
    "log"
    "fmt"
    "path/filepath"
)

const (
    B  = 1
    KB = 1024 * B
    MB = 1024 * KB
    GB = 1024 * MB
)

func DirSize(path string) (int64, error) {
    var size int64
    err := filepath.Walk(path, func(_ string, info os.FileInfo, err error) error {
        if err != nil {
            return err
        }
        if !info.IsDir() {
            size += info.Size()
        }
        return err
    })
    return size, err
}

func main() {
    dirs := []string{"./containers", "./testfolder", "./workspace"}

    for _, dir := range dirs {
        size, err := DirSize(dir)
        if err != nil {
            log.Printf("failed to calculate size of directory %s: %v\n", dir, err)
            continue
        }
        fmt.Printf("%s --> %.2f GB\n", dir, float64(size)/float64(GB))
    }
}

Go相关问答推荐

区分Terminal和Hook Zerolog Go中的错误级别日志(log)输出

如果添加构建标签,gopls将停止工作

正在使用terratest执行terraform脚本测试,但遇到错误退出状态1

为什么Slices包中的函数定义Slice参数的类型参数?

Golang中的泛型 struct /接口列表

Golang Gorm Fiber / argon2.Config 未定义

Go Gin:验证 base64

当我使用 CircleCI 构建 Go Image 时,我得到runtime/cgo: pthread_create failed: Operation not allowed

Golang chromedp Dockerfile

Secrets Manager Update Secret - Secret String 额外的 JSON 编码

无法使用带有 422 的 go-github 创建提交 - 更新不是快进

如何将一片 map 转换为一片具有不同属性的 struct

无法使用 Golang 扫描文件路径

数据流中的无根单元错误,从 Golang 中的 PubSub 到 Bigquery

为什么此代码在运行命令 error="exec: not started" 时出现错误?

如何通过组合来自不同包的接口来创建接口?

如何在gin中获取参数值数组

如何在 Windows 中使用 github.com/AllenDang/giu 和 github.com/gordonklaus/portaudio 构建 GO 程序

使用不安全的指针从 [] 字符串中获取值

如何解决在mac m1中运行gcc失败退出状态1?