我有一个非常简单的测试程序,可打印出以下数字。
即
int main(int argc, char* argv[])
struct statvfs vfs;
statvfs(argv[1], &vfs);
printf("f_bsize (block size): %lu\n"
"f_frsize (fragment size): %lu\n"
"f_blocks (size of fs in f_frsize units): %lu\n"
"f_bfree (free blocks): %lu\n"
"f_bavail free blocks for unprivileged users): %lu\n"
"f_files (inodes): %lu\n"
"f_ffree (free inodes): %lu\n"
"f_favail (free inodes for unprivileged users): %lu\n"
"f_fsid (file system ID): %lu\n"
"f_flag (mount flags): %lu\n"
"f_namemax (maximum filename length)%lu\n",
vfs.f_bsize,
vfs.f_frsize,
vfs.f_blocks,
vfs.f_bfree,
vfs.f_bavail,
vfs.f_files,
vfs.f_ffree,
vfs.f_favail,
vfs.f_fsid,
vfs.f_flag,
vfs.f_namemax);
return 0;
}
打印出来:
f_bsize (block size): 4096
f_frsize (fragment size): 4096
f_blocks (size of fs in f_frsize units): 10534466
f_bfree (free blocks): 6994546
f_bavail free blocks for unprivileged users): 6459417
f_files (inodes): 2678784
f_ffree (free inodes): 2402069
f_favail (free inodes for unprivileged users): 2402069
f_fsid (file system ID): 12719298601114463092
f_flag (mount flags): 4096
f_namemax (maximum filename length)255
打印输出root fs:
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sda5 42137864 14159676 25837672 36% /
但这里是我困惑的地方。
25837672 + 14159676!= 42137846(实际上是39997348)
因此,如果我要进行计算14159676/42137864 * 100,我得到33%而不是36%作为df打印。
但如果我计算
14159676/39997348 * 100我得到35%。
为什么所有的差异以及在哪里获得号码42137864?它是否与某些转换为1k块相比,实际系统块大小为4k?
这将集成到我的缓存应用程序中,告诉我何时驱动器处于某个阈值...例如在我开始释放大小为2 ^ n大小的固定大小的块之前90%。 所以我所追求的是一个能让我使用得相当准确的函数。
编辑: 我现在可以匹配df打印。除了使用百分比。这让我们想知道这一切是多么准确。什么是片段大小?
unsigned long total = vfs.f_blocks * vfs.f_frsize / 1024;
unsigned long available = vfs.f_bavail * vfs.f_frsize / 1024;
unsigned long free = vfs.f_bfree * vfs.f_frsize / 1024;
printf("Total: %luK\n", total);
printf("Available: %luK\n", available);
printf("Used: %luK\n", total - free);
EDIT2:
unsigned long total = vfs.f_blocks * vfs.f_frsize / 1024;
unsigned long available = vfs.f_bavail * vfs.f_frsize / 1024;
unsigned long free = vfs.f_bfree * vfs.f_frsize / 1024;
unsigned long used = total - free;
printf("Total: %luK\n", total);
printf("Available: %luK\n", available);
printf("Used: %luK\n", used);
printf("Free: %luK\n", free);
// Calculate % used based on f_bavail not f_bfree. This is still giving out a different answer to df???
printf("Use%%: %f%%\n", (vfs.f_blocks - vfs.f_bavail) / (double)(vfs.f_blocks) * 100.0);
f_bsize (block size): 4096
f_frsize (fragment size): 4096
f_blocks (size of fs in f_frsize units): 10534466
f_bfree (free blocks): 6994182
f_bavail (free blocks for unprivileged users): 6459053
f_files (inodes): 2678784
f_ffree (free inodes): 2402056
f_favail (free inodes for unprivileged users): 2402056
f_fsid (file system ID): 12719298601114463092
f_flag (mount flags): 4096
f_namemax (maximum filename length)255
Total: 42137864K
Available: 25836212K
Used: 14161136K
Free: 27976728K
Use%: 38.686470%
matth@kubuntu:~/dev$ df
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sda5 42137864 14161136 25836212 36% /
我得到38%不是36.如果按f_bfree计算我得到33%。是df错了还是这个从来都不准确?如果是这种情况,那么我希望倾向于保守。
答案 0 :(得分:16)
df
的数据可能基于f_bavail
,而不是f_bfree
。您可能会发现查看source code to df有助于了解它是如何运作的。它有许多需要处理的边缘情况(例如,当使用的空间超过非root用户可用的空间量时),但正常情况的相关代码在这里:
uintmax_t u100 = used * 100;
uintmax_t nonroot_total = used + available;
pct = u100 / nonroot_total + (u100 % nonroot_total != 0);
换句话说,100 * used / (used + available)
,向上舍入。从您的df输出中插入值会产生100 * 14159676 / (14159676 + 25837672) = 35.4015371
,向上舍入为36%,就像计算df
一样。
答案 1 :(得分:4)
在编辑#2上,需要将Usage%计算更新为与df输出匹配:
100.0 * (double) (vfs.f_blocks - vfs.f_bfree) / (double) (vfs.f_blocks - vfs.f_bfree + vfs.f_bavail)
推理:
使用= f_blocks - f_bfree
Avail = f_bavail
df%=已使用/(已使用+可用)
答案 2 :(得分:2)
这是我最接近匹配使用百分比的df -h
输出:
const uint GB = (1024 * 1024) * 1024;
struct statvfs buffer;
int ret = statvfs(diskMountPoint.c_str(), &buffer);
const double total = ceil((double)(buffer.f_blocks * buffer.f_frsize) / GB);
const double available = ceil((double)(buffer.f_bfree * buffer.f_frsize) / GB);
const double used = total - available;
const double usedPercentage = ceil((double)(used / total) * (double)100);
return usedPercentage;
答案 3 :(得分:1)
statvfs指标有点令人困惑。您可以使用psutil源代码作为示例,了解如何以字节为单位获取有意义的值:https://github.com/giampaolo/psutil/blob/f4734c80203023458cb05b1499db611ed4916af2/psutil/_psposix.py#L119
答案 4 :(得分:1)
这里是模仿df
行为的实现:
#include <string>
#include <sys/statvfs.h>
double amountOfDiskSpaceUsed(const std::string& filePath)
{
// Based on the implementation in https://github.com/coreutils/coreutils/blob/master/src/df.c
// See how PCENT_FIELD and IPCENT_FIELD are calculated.
struct statvfs diskInfo;
statvfs(filePath.c_str(), &diskInfo);
const auto total = static_cast<unsigned long>(diskInfo.f_blocks);
const auto available = static_cast<unsigned long>(diskInfo.f_bavail);
const auto availableToRoot = static_cast<unsigned long>(diskInfo.f_bfree);
const auto used = total - availableToRoot;
const auto nonRootTotal = used + available;
return 100.0 * static_cast<double>(used) / static_cast<double>(nonRootTotal);
}
例如它可能返回39.623889
,而df
输出40%
(四舍五入的值)。
答案 5 :(得分:0)
每次处理此问题时,我似乎都会感到困惑。我希望以下C代码对寻找已用空间百分比的人有所帮助:
/*
* It is helpful to use a picture to aid the calculation of disk space.
*
* |<--------------------- f_blocks ---------------------------->|
* |<---------------- f_bfree ------------------>|
*
* ---------------------------------------------------------------
* | USED | f_bavail | Reserved for root |
* ---------------------------------------------------------------
*
* We want the percentage of used blocks vs. all the
* non-reserved blocks: USED / (USED + f_bavail)
*/
fsblkcnt_t used = fs_stats.f_blocks - fs_stats.f_bfree;
double fraction_used = (double) used / ((double) used + (double) fs_stats.f_bavail);
uint8_t percent_used = (uint8_t) ((fraction_used * 100.0) + 0.5); // Add 0.5 for rounding