【问题标题】:How to get total size of a folder in C with recursivity?如何通过递归获得C中文件夹的总大小?
【发布时间】:2014-03-01 10:20:56
【问题描述】:

所有文件夹的大小为 4096 B。

如何获取包含所有文件大小的文件夹的总大小?

例如:

> Dir1 (4096)
> -- File1.txt (100)
> -- Dir 2 (4096)
> ---- File2.txt (100)

当我尝试获取 Dir1 的大小时,它给了我 4096。 我希望得到的预期答案是 8392

另一个例子:

DirA (4096)
-- FileA (100)
-- FileB (100)

总数应该是4296

我正在尝试找出算法,但我找不到检测它是否是文件夹的方法。对不起下面的“粗俗”代码......

DIR *dir;
struct dirent *dp;
struct stat fileStat;
    int getTotalDirSize()
    {
        while()
        {
            if(/*Detect Folder/Directory*/)
            {
            totalSize += 4096;
                getTotalDirSize();
            }
            else
            {
                totalSize += fileSize;
            }

        }

        return totalSize;
    }

注意:我使用 struct stat 来获取大小和文件/文件夹名称。

【问题讨论】:

  • 不相关:不知道它是否是一个真实的词,但我将它添加到我的白话中,并且无论如何我明天一有机会就会向它发送垃圾邮件。
  • 在相关的注释中,stat 的属性之一是st_mode 成员,如果你用S_ISDIR() 包装它并且它的答案是真的,它就是一个目录。注意... 文件夹以及符号链接。并且不要忘记dirent() 可以(并且通常会)在每次前进时都会破坏其名称缓冲区,因此如果您以后需要使用文件名,请进行复制。对于文件中的所有内容,只需不断总结大小即可。
  • 我建议您重用来自 GNU coreutils 的 du(1) 代码,而不是自己酿造。或者看看来自 BSD 用户空间的类似实用程序。
  • yes .. du(1) 是找出任何特定文件夹大小的好方法,例如 try as du -h --max-depth=0 /home/

标签: c recursion directory size stat


【解决方案1】:

它与 stat 一起使用,但只有您需要做的是 给出 stat 的完整路径,就像在您的示例 Dir1->4096B 中那样,然后如果您想知道 File1.txt 的大小,请使用像这样的统计:

strcpy(str,Dir1);   //str is a string
strcat(str,"/");
strcat(str,filename);

然后在 stat 中使用str 来获取该文件的大小。我认为在这里你必须使用 dirent 结构 和 DIR 文件夹及其内容。

要查找文件夹,请使用 d_type = 4 作为 dirent 结构 指针。对于递归操作,将所有内容放在一个单独的函数中并递归调用它,直到文件夹搜索完成。

struct stat buf;
DIR *dptr;
struct dirent *sdir;
int size=0;
char str[100];

dptr=opendir(folder);
while(sdir=readdir(dptr))
{
    if(sdir->d_type==4)
    {
        if(sdir->d_name[0]!='.')
        {
            stat(sdir->d_name,&buf);
            size=buf.st_size;
            pf("size=%d\n",size);
        }
    }
    else
    {
        strcpy(str,folder);
        strcat(str,"/");
        strcat(str,sdir->d_name);
        stat(str,&buf);
        size+=buf.st_size;
        pf("size=%d\n",size);
    }
}

【讨论】:

  • 如果我的函数具有以下形式,我应该如何递归地使用我的函数: void goNextDir(char *path[]){...} ?使用 goNextDir(str);它给出了错误。
  • 取一个有两个参数的函数。一个是文件夹/文件名,另一个是路径。
【解决方案2】:

当我遇到这个线程和其他一些在 SO 上处理相同或类似问题时,我只是在寻找解决这个问题的方法(我在最后发现了 3 个不同的代码,旨在计算文件夹的总大小纯 C)。不幸的是,它们都没有自己工作或不完整,所以我不得不改进它们(将一个合并到另一个),然后我得到了以下完整且有效的代码和示例(应该放在 main.c 文件中,确切的文件夹已更改,然后运行)。希望对你有帮助!

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <stdint.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>

int readFolderSize(int* totalSize, char* folder)
{
    char fullPath[256];
    struct dirent *dirData;
    struct stat buffer;
    int exists;
    DIR *poDir;
    int resp = EXIT_SUCCESS;

    poDir = opendir(folder);

    if (poDir == NULL)
    {
        perror("general_getFolderSize: poDir fail!");

        return EXIT_FAILURE;
    }

    while ((dirData = readdir(poDir)))
    {
        if (dirData == NULL)
        {
            const unsigned int err = errno;

            fprintf(stderr, "general_getFolderSize: Failed in readdir (%u)\n",err);

            resp = EXIT_FAILURE;

            continue;
        }

        //
        if (dirData->d_type == DT_DIR)
        {
            if (dirData->d_name[0] != '.')
            {
                //printf("general_getFolderSize: Is a directory: %s\n", dirData->d_name);

                strcpy(fullPath,folder);
                strcat(fullPath,"/");
                strcat(fullPath,dirData->d_name);

                //printf("general_getFolderSize: Accessing dir: %s\n", fullPath);

                if (readFolderSize(totalSize,fullPath) == EXIT_FAILURE)
                    resp = EXIT_FAILURE;
            }
        }
        else
        {
            strcpy(fullPath,folder);
            strcat(fullPath,"/");
            strcat(fullPath,dirData->d_name);

            exists = stat(fullPath,&buffer);

            if (exists < 0)
            {
                const unsigned int err = errno;

                fprintf(stderr, "general_getFolderSize: Failed in stat (file) %s: %u\n", fullPath,err);

                resp = EXIT_FAILURE;

                continue;
            }
            else
            {
                (*totalSize) += buffer.st_size;

                //printf("general_getFolderSize: Item size (file) (%s): %d\n",fullPath,(int)buffer.st_size);
            }
        }
    }

    closedir(poDir);

    return resp;
}

/*!
 * \brief general_getFolderSize returns the size of a folder in bytes.
 * \param folder is the name of the folder (preferentially without a '/' at the end)
 * \param totalSize is a pointer where the result value is given
 * \return
 */
int general_getFolderSize(char* folder, int* totalSize)
{
    printf("general_getFolderSize: Start\n");

    //
    if (readFolderSize(totalSize,folder) == EXIT_FAILURE)
    {
        perror("general_getFolderSize: Call to readFolderSize failed!");

        return EXIT_FAILURE;
    }

    //
    printf("general_getFolderSize: Stop\n");

    return EXIT_SUCCESS;
}

int main()
{
    int folderSize;

    if (general_getFolderSize("/home/maiquel/Documents/TEMP/maindir",&folderSize) == EXIT_FAILURE)
    {
        printf("Error reading folder size!");
    }
    else
    {
        printf("Folder size: %d b (%d kb / %d Mb)\n", folderSize, folderSize/1024, folderSize/(1024 * 1024));
    }

    return EXIT_SUCCESS;
}

P.s.:虽然我知道 EXIT_SUCCESSEXIT_FAILURE 不应该用作函数返回值,但我更愿意这样做,而不是为了简化代码而创建新定义。

【讨论】:

    猜你喜欢
    • 2011-01-29
    • 2020-01-13
    • 2018-10-10
    • 2018-12-17
    • 2018-10-10
    • 2012-05-29
    • 1970-01-01
    • 1970-01-01
    • 2012-06-16
    相关资源
    最近更新 更多