计算C中目录的大小

tvmytwxo  于 2023-02-07  发布在  其他
关注(0)|答案(3)|浏览(181)

我想递归地计算目录(path)的大小。在我当前的代码中,我有一个函数来识别它是目录还是文件,如果它是目录,它会调用子目录(file)的函数,如果它是文件,它会添加到totalSize变量中。但是,我当前的代码没有返回任何意味着某个地方有错误的信息。下面是我的代码-

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

void getsize(const char *path,int* totalSize);

int main()
{
    int total = 0;
    char path [] = "C:\\Users\\abbas\\Desktop\\Leetcode airplane";
    getsize(path,&total);
    printf("%d",total);
    return total;

}

void getsize(const char *path,int* totalSize)
{
    struct dirent *pDirent;
    struct stat buf;
    struct stat info;
    DIR *pDir;
    int exists;
    char str[100];
    pDir = opendir (path);
    while ((pDirent = readdir(pDir)) != NULL)
    {
        stat(pDirent->d_name,&info);
        if(S_ISDIR(info.st_mode))
        {
            strcpy(str,path);
            strcat(str,"/");
            strcat(str,pDirent->d_name);
            getsize(str,totalSize);
        }
        else
        {
            strcpy(str,path);
            strcat(str,"/");
            strcat(str,pDirent->d_name);
            exists = stat(str,&buf);
            if (exists < 0)
            {
                continue;
            }
            else
            {
                (*totalSize) += buf.st_size;
            }

        }
    }
    closedir(pDir);
}
pkln4tw6

pkln4tw61#

1.包含字符串. h。
1.任意固定大小的str[100]是有问题的。如果你在Linux上使用linux/limits. h并使用str[PATH_MAX]或更好的pathconf(path, _PC_NAME_MAX)。在任何情况下,你都应该确保缓冲区足够大(例如使用snprintf()),或者动态分配缓冲区。
1.您需要排除...,否则将导致无限循环(path/../path/..)。

  1. stat(pDirent->d_name,&info)失败,因为您需要stat()path/pDirect->d_name,而不仅仅是pDirect->d_name
    1.(未修复)可能是snprintf(path2, sizeof path2, "%s%s%s", path, PATH_SEP, pDirenv->d_name),而不是strcpy()strcat()
    1.检查函数的返回值,否则你就是在浪费时间。
    1.没有必要在同一路径上执行两个stat()调用,所以只需使用(*totalSize) += buf.st_size;
    1.(未修复)在Windows上,请考虑将_stat64()与结构体__stat64(@AndrewHenle)的地址一起使用。
    1.我假设你只需要文件的大小。
    1.(未修复)如果getsize()返回大小,而不是使用int *totalSize输出参数,则会更自然。
    1.(未修复)请考虑使用nftw()(或较旧的ftw())遍历树。
    请注意,程序现在接受路径通过命令行进行测试.
#include <dirent.h>
#include <errno.h>
#include <linux/limits.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

const char PATH_SEP =
#ifdef _WIN32
    "\\";
#else
     "/";
#endif

void getsize(const char *path,int *totalSize) {
    struct dirent *pDirent;
    DIR *pDir = opendir (path);
    while ((pDirent = readdir(pDir)) != NULL) {
        if(
            !strcmp(pDirent->d_name, ".") ||
            !strcmp(pDirent->d_name, "..")
        )
            continue;

        char path2[PATH_MAX];
        strcpy(path2, path);
        strcat(path2, PATH_SEP);
        strcat(path2, pDirent->d_name);
        struct stat info;
        if(stat(path2, &info) == -1) {
            perror("stat");
            return;
        }
        if(S_ISDIR(info.st_mode))
            getsize(path2, totalSize);
        else if(S_ISREG(info.st_mode))
            (*totalSize) += info.st_size;
    }
    closedir(pDir);
}

int main(argc, char *argv[]) {
    if(argc != 2) {
        printf("usage: your_program path\n");
        return 1;
    }
    int total = 0;
    getsize(argv[1], &total);
    printf("%d\n",total);
}

和示例测试:

$ mkdir -p 1/2
$ dd if=/dev/zero of=1/file count=123
123+0 records in
123+0 records out
62976 bytes (63 kB, 62 KiB) copied, 0.000336838 s, 187 MB/s
$ dd if=/dev/zero of=1/2/file count=234
234+0 records in
234+0 records out
119808 bytes (120 kB, 117 KiB) copied, 0.0015842 s, 75.6 MB/s
$ echo $((62976 + 119808))
182784
$ ./your_program 1
182784
oxiaedzo

oxiaedzo2#

我认为你的代码的主要错误在于递归逻辑。
引用《C编程语言》第183页:
每个目录始终包含其自身的条目(称为.“")和其父目录的条目(..”");这些必须被跳过,否则程序将永远循环。
因此,您可以尝试在while循环的开头添加以下if测试:

while ((pDirent = readdir(pDir)) != NULL)
{
    if (strcmp(pDirent->d_name, ".") == 0
        || strcmp(pDirent->d_name, "..") == 0)
        continue;  /* skip self and parent */
    /* ... */
}

尽管如此,可能还有其他错误,但我认为这一个是最重要的。

13z8s7eq

13z8s7eq3#

练习安全编码。

低于风险缓冲区溢出。

// Risky
        strcpy(str,path);
        strcat(str,"/");
        strcat(str,pDirent->d_name);

编码完成后,

int len = snprintf(str, sizeof str, "%s/%s", path, pDirent->d_name);
if (len < 0 || (unsigned) len >= sizeof str) {
  fprintf(stderr, "Path too long %s/%s\n", path, pDirent->d_name);
  exit (-1);  
}

然后代码很容易错误地在"."".."上递归,导致OP自我发现一个关键问题。
这有助于更快的代码生产和更有弹性的代码。节省OP时间。

相关问题