如何在Posix系统中获取总可用磁盘空间?

9

我正在编写一个跨平台应用程序,需要获取可用的磁盘空间。对于posix系统(Linux和MacOS),我使用statvfs。我创建了这个C++方法:

long OSSpecificPosix::getFreeDiskSpace(const char* absoluteFilePath) {
   struct statvfs buf;

   if (!statvfs(absoluteFilePath, &buf)) {
      unsigned long blksize, blocks, freeblks, disk_size, used, free;
      blksize = buf.f_bsize;
      blocks = buf.f_blocks;
      freeblks = buf.f_bfree;

      disk_size = blocks*blksize;
      free = freeblks*blksize;
      used = disk_size - free;

      return free;
   }
   else {
      return -1;
   }
}

很不幸,我得到了一些奇怪的值,无法理解。例如: f_blocks = 73242188 f_bsize = 1048576 f_bfree = 50393643 ...

这些值是以位、字节或其他形式表示的吗?我在stackoverflow上读到这些应该是字节,但是那么我将得到可用字节数的总数为: f_bsize*f_bfree = 1048576*50393643 但这意味着49212.542GB...太多了...

我是不是在代码或其他方面做错了什么? 谢谢!


你使用的文件系统块大小为1048576吗? - Peter G.
这是Mac OS Extended(区分大小写,日志记录)。现在我正在使用Mac,但据我所知,这应该可以工作。 - Luca Carlon
除了你的块大小和所谓的70TB驱动器有些奇怪之外,要注意32位OSX上的“long”只有32位。即使你有正确的数字,这可能对于你的块数来说已经足够大了,但对于你的字节数来说还不够大。像4GB这样大的驱动器可以从专业供应商那里轻松获得;-) - Steve Jessop
除了返回类型错误的问题,还有其他原因导致结构中出现奇怪的值吗?还有其他获取这些值的方法吗?谢谢! - Luca Carlon
4
啊,现在我仔细看一下,检查一下 f_bsizef_frsize 是否相等。我敢打赌它们不相等。块数和可用块数是指 f_frsize,而不是 f_bsize - Steve Jessop
4个回答

8
我对OSX不是很熟悉,无法确定这是否是答案,但是f_blocksf_bfree实际上是指“基本块”或“片段”(它们的大小为buf.f_frsize字节),而不是“文件系统块大小”(它是buf.f_bsize字节):

http://www.opengroup.org/onlinepubs/009695399/basedefs/sys/statvfs.h.html

f_bsize只是一个提示,用于I/O操作的首选大小,它不一定与文件系统如何划分有关。


3
以下几行代码:
disk_size = blocks*blksize;
free = freeblks*blksize;

如果使用巨大的硬盘,可能会导致溢出。

我之前也遇到了奇怪的结果,后来发现我的硬盘容量是455GiB,请在进行乘法运算之前将blocks、blksize和freeblks变量强制转换为unsigned long long类型。

代码示例:

unsigned long long disk_size = (unsigned long long) (blocks) * (unsigned long long) (blksize)

我看到很多类似的问题,但没有人在答案中注意到这一点。


好的发现!我也看到了这些奇怪的数字被转换成(unsigned long long) - lppier

2

我认为前两个回答是正确和有用的。然而,我通过简单地将函数statvfs替换为函数statfs来解决了问题。块大小随后变为4096,一切似乎都是正确的。 谢谢!


我看不出statfs在OS X上被弃用了。而且,statfs生成了正确的值。 - codingFriend1
我也看不到这个链接:https://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man2/statfs.2.html。 - Luca Carlon
苹果文档在statvfs文档结尾处说:statvfs()和fstatvfs()函数符合IEEE Std 1003.1-2001(“POSIX.1”)标准。根据标准化,可移植应用程序无法依赖这些函数返回任何有效信息。此实现尝试提供尽可能多的有用信息,由底层文件系统提供,受指定数据类型限制。 - Sergi0

1
uint64_t userAvailableFreeSpace()
{
    struct statvfs stat;
    struct passwd *pw = getpwuid(getuid());
    if ( NULL != pw && 0 == statvfs(pw->pw_dir, &stat) )
    {
        uint64_t freeBytes = (uint64_t)stat.f_bavail * stat.f_frsize;
        return freeBytes;
    }
    return 0ULL;
}

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