使用Go获取可用磁盘空间的数量

47

基本上,我想要df -h的输出,其中包括卷的可用空间和总大小。解决方案需要在Windows、Linux和Mac上运作,并用Go编写。

我查阅了Go文档中的ossyscall,但没有找到合适方法。在Windows上,即使是命令行工具也要么不方便(dir C:\),要么需要特权(fsutil volume diskfree C:\)。肯定还有其他方法可以做到这一点,只是我还没有发现...

更新:
根据nemo的答案和邀请,我提供了一个跨平台Go包来实现此功能。


我所知道的是,你可以通过cgo降级到C语言:编写freespace_windows.go和freespace_{linux,bsd}.go,并使用GetDiskFreeSpacestatvfs来获取可用空间。 - twotwotwo
3个回答

75
在POSIX系统上,您可以使用sys.unix.Statfs
打印当前工作目录的可用空闲空间示例(以字节为单位):
import "golang.org/x/sys/unix"
import "os"

var stat unix.Statfs_t

wd, err := os.Getwd()

unix.Statfs(wd, &stat)

// Available blocks * size per block = available space in bytes
fmt.Println(stat.Bavail * uint64(stat.Bsize))

对于Windows系统,您也需要使用系统调用的方法。示例(源代码,已更新以匹配新的sys/windows):

import "golang.org/x/sys/windows"

var freeBytesAvailable uint64
var totalNumberOfBytes uint64
var totalNumberOfFreeBytes uint64

err := windows.GetDiskFreeSpaceEx(windows.StringToUTF16Ptr("C:"),
    &freeBytesAvailable, &totalNumberOfBytes, &totalNumberOfFreeBytes)

随意编写一个提供跨平台功能的软件包。 关于如何实现跨平台功能,请参阅构建工具帮助页面

2
感谢您详细的帖子。我已经更新了我的问题,包括链接到我的实现此操作的软件包。 - Rick Smith
1
@bantl23 Bavail 是非特权用户可用的块数。Bfree 只是空闲块的总数。 - nemo
5
在 POSIX 系统上,您可以使用 syscall.Statfs。不幸的是,这不是符合 POSIX 标准的系统调用。符合 POSIX 标准的调用是 "statvfs"。Statfs 在不同的 *NIX 操作系统上提供不同的信息。为什么 Go 的开发者选择实现不符合 POSIX 标准的版本超出了我的理解范围。 - Jasper Siepkes
2
从这个包的文档来看:“已弃用:此包已锁定。调用者应使用 golang.org/x/sys 存储库中对应的包。https://golang.org/pkg/syscall/#Statfs" - Brett Holman
1
@BrettHolman 完全正确,已更新答案。 - nemo
显示剩余4条评论

9

这是我基于github.com/shirou/gopsutil库编写的df -h命令版本。

package main

import (
    "fmt"

    human "github.com/dustin/go-humanize"
    "github.com/shirou/gopsutil/disk"
)

func main() {
    formatter := "%-14s %7s %7s %7s %4s %s\n"
    fmt.Printf(formatter, "Filesystem", "Size", "Used", "Avail", "Use%", "Mounted on")

    parts, _ := disk.Partitions(true)
    for _, p := range parts {
        device := p.Mountpoint
        s, _ := disk.Usage(device)

        if s.Total == 0 {
            continue
        }

        percent := fmt.Sprintf("%2.f%%", s.UsedPercent)

        fmt.Printf(formatter,
            s.Fstype,
            human.Bytes(s.Total),
            human.Bytes(s.Used),
            human.Bytes(s.Free),
            percent,
            p.Mountpoint,
        )
    }
}


这在Windows 10和MacOS 11.3上运行得非常好。谢谢。 - jftuga

8

Minio有一个跨平台、似乎保持良好的磁盘使用情况展示包(GoDoc):

import (
        "github.com/minio/minio/pkg/disk"
        humanize "github.com/dustin/go-humanize"
)

func printUsage(path string) error {
        di, err := disk.GetInfo(path)
        if err != nil {
            return err
        }
        percentage := (float64(di.Total-di.Free)/float64(di.Total))*100
        fmt.Printf("%s of %s disk space used (%0.2f%%)\n", 
            humanize.Bytes(di.Total-di.Free), 
            humanize.Bytes(di.Total), 
            percentage,
        )
}

这段代码实际上提供了来自 du -h 命令输出的数据,例如目录使用情况,而不是请求的 df -h 命令提供的磁盘使用情况。无论如何,这可能是使用 minio 包的一个很好的示例。 - Roman Shishkin
2
发现go模块github.com/minio/minio@upgrade(v0.0.0-20230424202818-8fd07bcd51cf),但不包含package github.com/minio/minio/pkg/disk。 - Milad Jahandideh
该软件包现在是github.com/minio/minio/internal/disk,不能使用。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接