【问题标题】:Get the size of a directory recursively - C递归获取目录的大小 - C
【发布时间】:2017-01-11 00:29:16
【问题描述】:

我正在尝试以递归方式获取目录的大小,但我只会遇到段错误。我真的看不出我错在哪里,有人可以帮助我吗? 附言我不需要验证文件是否存在,这只是我必须编写的另一个函数的尝试。

代码如下:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <stdlib.h>
#include <limits.h>

int main(int argc, char * argv[])
{
  printf("%d\n", size(argv[1]));
  return 0;
}

int is_folder(char * path)
{
    struct stat path_stat;
    stat(path, &path_stat);
    return !(S_ISREG(path_stat.st_mode));
}

int size(char * name)
{
  int dir_size = 0;
  struct dirent * pDirent;
  DIR * pDir = opendir(name);
  while ((pDirent = readdir(pDir)) != NULL)
  {
    char buf[PATH_MAX + 1];
    realpath(pDirent->d_name, buf);
    if (is_folder(buf))
    {
      size(buf);
    }
    else
    {
      struct stat st;
      stat(buf, &st);
      int sz = st.st_size;
      dir_size += sz;
    }
  }
   return dir_size;
}

【问题讨论】:

  • 您是否尝试过使用调试器来识别导致段错误的行?
  • 由于我们不知道你是如何运行程序的,所以main 的第一行应该是if(argc &lt; 2) exit(1);。同样,您省略检查来自statrealpath 的返回值。
  • 调试器这样说:0x00007ffff7ad2fe6 in readdir64 () from /lib64/libc.so.6
  • 好的,我明白了:调试器说问题出在 size(buf) --> 递归。似乎 buf 的值为 0,即 NULL 值。但为什么? while 语句应该排除这种情况。
  • 您需要将目录名称与d_name 连接以获取文件的完整路径。 realpath() 不会这样做。

标签: c recursion directory size


【解决方案1】:

基于您的代码,下面是我能够重现 du -sk 返回的最接近的内容:

#include <stdio.h>
#include <sys/stat.h>
#include <dirent.h>
#include <limits.h>
#include <string.h>

off_t directorySize(char *directory_name)
{
    off_t directory_size = 0;

    DIR *pDir;

    if ((pDir = opendir(directory_name)) != NULL)
    {
        struct dirent *pDirent;

        while ((pDirent = readdir(pDir)) != NULL)
        {
            char buffer[PATH_MAX + 1];

            strcat(strcat(strcpy(buffer, directory_name), "/"), pDirent->d_name);

            struct stat file_stat;

            if (stat(buffer, &file_stat) == 0)
            {
                directory_size += file_stat.st_blocks * S_BLKSIZE;
            }

            if (pDirent->d_type == DT_DIR)
            {
                if (strcmp(pDirent->d_name, ".") != 0 && strcmp(pDirent->d_name, "..") != 0)
                {
                    directory_size += directorySize(buffer);
                }
            }
        }

        (void) closedir(pDir);
    }

    return directory_size;
}

int main(int argc, char *argv[])
{
    printf("%lldKiB\n", directorySize(argv[1]) / 1024);

    return 0;
}

我猜您看到的差异是由于目录占用了少量空间,您需要将这些空间包含在您的总数中,并且文件空间使用是分块的,因此您需要计算块数,而不是字节数。

【讨论】:

  • 这个答案让我大开眼界。谢谢。你。我不知道为什么,但我在 linux 源代码上尝试了你的算法,只返回了 660KB ......所以我把我的和你的混在一起了,我得到了 du -sh 完全相同的结果。我把它贴在这里。
【解决方案2】:

花了一晚尝试如何找到与 du -sh 报告的大小相同的大小:我写了这个,它似乎也适用于大型目录(例如 750MB 或更大的 linux 源)。

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <dirent.h>
#include <stdlib.h>
#include <limits.h>

long folder_size(char *);

int main(int argc, char * argv[])
{
  if (argc < 2)
  {
    exit(1);
  }
  printf("%ld\n", mysize(argv[1]));
  return 0;
}

int not_folder(char * path)
{
    struct stat path_stat;
    stat(path, &path_stat);
    return (S_ISREG(path_stat.st_mode));
}

long folder_size(char * name)
{
  long dir_size = 0L;
  struct dirent * pDirent;
  DIR * pDir = opendir(name);
  while ((pDirent = readdir(pDir)))
  {
    if (strcmp (pDirent->d_name, "..") != 0 && strcmp (pDirent->d_name, ".") != 0)
    {
      char buf[PATH_MAX];
      strcpy(buf, name);
      strcat(buf, "/");
      strcat(buf, pDirent->d_name);
      if (not_folder(buf))
      {
        struct stat st;
        stat(buf, &st);
        dir_size += st.st_blocks * S_BLKSIZE;
        printf("%s %ld\n", buf, (long)st.st_size);
      }
      else
      {
        dir_size += folder_size(buf);
      }
    }
  }
  (void) closedir(pDir);
  return dir_size;
}

【讨论】:

  • 1) 代码不检查stat() 的返回值。 2) st.st_blocks * S_BLKSIZE 可能会溢出。 3) dir_size += st.st_blocks * S_BLKSIZE; 可能会溢出。最好使用unsigned long long。 4)无需重复调用char buf[PATH_MAX]; strcpy(buf, name); strcat(buf, "/");只需在while循环之前运行一次,记录它的长度然后执行strcpy(buf + len, pDirent-&gt;d_name);
猜你喜欢
  • 1970-01-01
  • 2015-08-07
  • 2020-08-02
  • 2010-10-03
  • 1970-01-01
  • 2018-12-17
  • 2011-06-22
  • 2021-09-05
  • 2010-11-10
相关资源
最近更新 更多