编辑:正如@abhink指出的那样,没有调用Size()
。
我尝试了两种不同的go方法,然后与df
进行了比较。当然,所有3个都有不同的结果:
package main
import (
"os"
"syscall"
"fmt"
)
func main() {
disk := "/dev/sda1"
statout, err := os.Stat(disk)
if err != nil {
fmt.Errorf("Error %x", err)
os.Exit(1)
}
println("os.Stat Size : ", statout.Size())
var stat syscall.Statfs_t
syscall.Statfs(disk, &stat)
println("syscall.Statfs_t Type: ", stat.Type)
println("syscall.Statfs_t Bsize: ", stat.Bsize)
println("syscall.Statfs_t Blocks: ", stat.Blocks)
}
运行程序:
$ main
os.Stat Size : 0
syscall.Statfs_t Type: 16914836
syscall.Statfs_t Bsize: 4096
syscall.Statfs_t Blocks: 2560
并且df:
$ df /dev/sda1
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sda1 65792556 43694068 18726712 70% /var
网:
os.Stat()
提供0
但不是,但可能是操作系统问题。syscall.Statfs()
提供2560个块* 4096块大小= 10,485,760
。 df
给出65792556 1K块* 1024字节/ K = 67,371,577,344
如何在不安装块设备的情况下可靠地获得块设备的大小?
基本上,我正在寻找设备上ioctl
调用的等价物。
ioctl(fd,BLKGETSIZE64,&size)
答案 0 :(得分:5)
致电syscall.Statfs()
时,您必须通过路径才能安装设备,例如/
,而不是设备文件(不是/dev/sda1
)。在您的情况下,这是/var
。
您将获得类型为syscall.Statfs_t
的值的结果。解释:
var stat syscall.Statfs_t
if err := syscall.Statfs("/", &stat); err != nil {
panic(err)
}
size := stat.Blocks * uint64(stat.Bsize)
free := stat.Bfree * uint64(stat.Bsize)
avail := stat.Bavail * uint64(stat.Bsize)
fmt.Println("Size:", size)
fmt.Println("Free:", free)
fmt.Println("Available:", avail)
fmt.Println("Used:", size-free)
答案 1 :(得分:1)
OP询问如何获取块设备的大小。要获取块设备(或任何文件)的大小,可以使用io.SeekEnd将File.Seek移至文件末尾并读取返回的位置。将python和C归功于其他人。
运行下面的示例getsize.go
显示:
$ sudo go run getsize.go /dev/sda
/dev/sda is 256060514304 bytes.
lsblk --bytes /dev/device
将为您提供相同的信息。那就是块设备可以存储多少数据。
Statfs_t
路径和df /path/to/mounted/filesystem
将为您提供有关在提供的路径处安装的文件系统中可以存储多少数据的信息。文件系统的开销取决于文件系统的详细信息,可能在2-5%的范围内,并且还要跟踪Free
或Used
有多少空间。
据我所知,没有任何api可以提供有关块设备上已卸载文件系统的信息。 dumpe2fs
可以为您提供ext {2,3,4}文件系统的信息。可能存在用于其他文件系统的工具。这样的工具是特定于文件系统的。挂载文件系统时,Linux内核的文件系统驱动程序将公开由df
返回的信息。
代码:
// getsize.go: get the size of a block device or file
package main
import (
"fmt"
"io"
"os"
)
func main() {
var path string
if len(os.Args) < 2 {
fmt.Println("Give path to file/disk")
os.Exit(1)
}
path = os.Args[1]
file, err := os.Open(path)
if err != nil {
fmt.Printf("error opening %s: %s\n", path, err)
os.Exit(1)
}
pos, err := file.Seek(0, io.SeekEnd)
if err != nil {
fmt.Printf("error seeking to end of %s: %s\n", path, err)
os.Exit(1)
}
fmt.Printf("%s is %d bytes.\n", path, pos)
}