c - nftw 目录的总大小与 du 输出不同

标签 c linux filesystems

我写了一小段代码,使用 nftw 系统调用来进行树行走。

int flags =0;
flags = flags | FTW_MOUNT;
int nopenfd = 10;

if( nftw( argv[1], sum_sizes, nopenfd, flags) == -1 )
  return EXIT_FAILURE;

使用此选项,nftw 不会扫描目录(如果它是挂载点)并取消引用符号链接(symbolic link)(默认行为)。

在每个文件 nftw 上调用这个函数:

/*total_size is the sum of each file/directory/link*/
long long int total_size, total_real_size = 0;

static int sum_sizes(const char *pathname, const struct stat *statbuf, int typeflag, struct FTW *ftwbuf)
{
/*if stat failed on the current file*/
if(typeflag == FTW_NS)
{
    printf("No stats (permissions ?) on %s", pathname);
    return 0;
}
total_size = total_size + (long long int ) statbuf->st_size;
total_real_size = total_real_size + (long long int ) ( statbuf->st_blocks * 512 );
return 0;
}

所以最后,我显示累积大小:

printf("total size: %lld (%0.2lf K %0.2lf M)\n", total_size,  (float)total_size /1024.0, (float)total_size /(1024.0*1024.0));
printf("total real size: %lld (%0.2lf K %0.2lf M)\n", total_real_size,  (float)total_real_size /1024.0, (float)total_real_size /(1024.0*1024.0));

当我将值与 du 进行比较时,我发现有一些差异

time ./scan_dir ~/        
====>
total size: 15208413390 (14851966.00 K 14503.87 M)
total real size: 15708553216 (15340384.00 K 14980.84 M)
block size : 4096 / fond. block size : 4096
fs size: 22.7895 G
./scan_dir ~/  0,03s user 0,24s system 98% cpu 0,277 total


time du -s ~/     
15119876    /home/cedlemo/
du -s ~/  0,07s user 0,22s system 98% cpu 0,287 total

注意:阅读 du 的手册页后,我知道 du 的行为与我的小应用程序 scan_dir 几乎相同(跳过挂载点,取消引用符号链接(symbolic link)并使用 1024 以计算 Ko 中的值)

似乎在我的应用程序中找到的更接近的值是实际大小(使用的 block )的总和,但该值并不完全相同。

造成这种差异的原因可能是什么? 我做错了什么?

最佳答案

默认情况下,du 遵循符号链接(symbolic link)。您的代码可以。

du -ks DIRECTORY/

相当于

find DIRECTORY/ -printf '%k\n' | awk '{s+=$1} END { printf "%.0f\n", s }'

它只查看每个目录条目一次,不遵循符号链接(symbolic link),不跨越挂载点,并输出 st_blocks*2 的总和(即以 1024 字节为单位)。换句话说,分配给文件和目录内容的 1024 字节单元的数量 -- 磁盘使用情况

另一方面,逻辑文件和目录大小的总和是

find DIRECTORY/ -printf '%s\n' | awk '{s+=$1} END { printf "%.0f\n", s / 1024.0 }'

这与磁盘使用无关,仅与存储在文件和目录中的表观信息量有关。通常这种测量仅限于常规文件,即

find DIRECTORY/ -type f -printf '%s\n' | awk '{s+=$1} END { printf "%.0f\n", s / 1024.0 }'

所以它基本上告诉用户,如果他们将所有文件连接成一个大文件,他们将获得多大的文件。它是否有意义还有待商榷,但许多用户认为它提供了很多信息。无论如何,这绝对是对磁盘使用情况的不同衡量。


在文件统计中(参见 man 2 fstat),st_blocks 描述了为文件内容分配了多少个 512 字节单元,而 st_size 是文件的逻辑大小文件。

大多数文件系统都支持稀疏文件。这意味着当您使用 truncate() 放大文件时,或者通过写入比当前文件大小更高的文件偏移量,文件系统根本不存储跳过的部分。但是,阅读该部分是完全可以的;它总是读作全零。因此,一个巨大的文件可能只消耗几个 block ,如果它大部分是零。 (准确地说,“跳过零”。创建文件时,仅写入零不会生成稀疏文件。您的应用程序需要跳过写入零,以生成稀疏文件。)

由于某些文件系统上的某些文件使用了间接 block , block 的数量也可能大于根据文件大小假设的 block 数。可能会分配和说明“额外的 block ”,因为文件是碎片化的或其他特殊的。在所有典型的文件系统上,无论如何,分配的 block 数都会四舍五入为文件系统分配大小的倍数。


在您的情况下,总大小 是文件的逻辑长度,如果您要将所有文件和目录的内容连接到一个文件中,包括符号链接(symbolic link)引用的任何重复项。

在您的情况下,总实际大小 描述了为所有文件和目录分配的磁盘空间总量,如果符号链接(symbolic link)被替换为原始文件的副本

如果你改成

flags = FTW_MOUNT | FTW_PHYS;

你应该得到匹配 du -stotal real size

关于c - nftw 目录的总大小与 du 输出不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18936326/

相关文章:

linux - 让应用程序签署文档,但不要让它看到 key

c++ - 动态内存分配是如何工作的

c - C 如何将宏标记识别为参数

c - mq_send 中的发送结构

cocoa - 从 Cocoa 应用程序在远程计算机内移动文件的最快方法?

iOS:如何重命名文档目录中的文件夹

mysql 链接外部资源 : . 压缩一个图片文件

c - 如何使用格式说明符从标准输入中读取

linux - Ansible 返回码错误 : 'dict object' has no attribute 'rc'

linux - 带有 --prof 选项的 Node 创建多个日志文件而不是一个 v8.log