使用 Golang 获取目录磁盘使用情况

Get Directory Disk Usage with Golang

提问人:siwm 提问时间:7/18/2023 最后编辑:siwm 更新时间:7/18/2023 访问量:258

问:

我尝试使用 golang 学习目录的磁盘用法,但下面的应用程序计算不正确。我不想使用 .我尝试过,但没有得到实际的目录大小。我在下面分享了相关的代码语句,正确的目录信息和应用程序的结果。filepath.Walkos.Stat()

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
统计 du

评论

1赞 siwm 7/18/2023
只感谢您的否决问题,高声誉先生!!

答:

4赞 VonC 7/18/2023 #1

我相信你滥用了系统调用。Statfs 函数:它返回文件系统统计信息,而不是单个目录或文件的大小。因此,您看到的输出不是单个目录的大小,而是这些目录所在的文件系统的整体磁盘使用情况。

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

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))
    }
}

这将遍历给定目录下的每个目录和文件,并汇总大小。
如果条目是目录,它将递归计算目录的大小。
虽然。。。此代码不会处理符号链接或其他特殊文件。


另一个选项用于遍历指定目录下的所有文件(包括子目录)的函数。
该函数采用两个参数:根目录和一个函数,该函数将为根目录的树中的每个文件或目录调用。
DirSizefilepath.Walkfilepath.Walk

在这里,对于它遇到的每个文件,它会将文件的大小添加到总大小中(忽略目录)。
由于自动为您处理递归遍历,因此它通常比手动编写递归函数更简单、更直接。
游乐场
filepath.Walk)

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))
    }
}

评论

0赞 siwm 7/18/2023
感谢您的快速回复。知道了。您的意见主要是我们必须从文件中获取所有信息以计算所有目录大小。如果我理解正确的话,此外,没有关于磁盘使用的官方功能。如果您不为我做出其他响应,首先我使用本地版本更改您的代码语句,然后我会签名解决。filestate.Walk()
0赞 VonC 7/18/2023
@swim我不知道,只有。你想让我包括一个例子吗?filestate.Walk()filepath.Walk()filepath.Walk()
0赞 siwm 7/18/2023
对不起,我的错误:)不,没问题,但如果你想举个例子,我将不胜感激。
0赞 siwm 7/18/2023
实际上,我期待有关于磁盘使用情况的golang官方功能。
0赞 VonC 7/18/2023
@swim 我用一个例子编辑了答案filepath.Walk()