如何在linux中以编程方式获取dir的大小?

发布于 2024-07-27 04:54:52 字数 237 浏览 7 评论 0原文

我想通过 C 程序获取 linux 中特定目录的确切大小。 我尝试使用 statfs(path,struct statfs &) 但它没有给出确切的大小。 我也尝试过 stat() 但它返回任何目录的大小为 4096 !

请建议我如何获取 dir 的确切大小,就像我们在“du -sh dirPath”命令之后得到的那样。

我也不想通过 system() 使用 du。

提前致谢。

I want to get the exact size of a particular dir in linux through a C program.
I tried using statfs(path,struct statfs &) but it doesn't give exact size.
I also tried with stat() but it returns size as 4096 for any dir !

Please suggest me the way through which I can get the exact size of dir just like we get after "du -sh dirPath" command.

Also I dont wanna use du through system().

Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

¢蛋碎的人ぎ生 2024-08-03 04:54:52

基于 Jim Plank 的 示例 帮助您入门:

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

int main( int argc, char **argv ) {
  DIR *d = opendir( "." );

  if( d == NULL ) {
    fprintf( stderr, "Cannot open current working directory\n" );
    return 1;
  }

  struct dirent *de;
  struct stat buf;
  int total_size = 0;

  for( de = readdir( d ); de != NULL; de = readdir( d ) ) {
    int exists = stat( de->d_name, &buf );

    if( exists < 0 ) {
      fprintf( stderr, "Cannot read file statistics for %s\n", de->d_name );
    } else {
      total_size += buf.st_size;
    }
  }

  closedir( d );
  printf( "%d\n", total_size );

  return 0;
}

注释、注意事项和读者问题:

  • 此示例不完整。 请参阅 Plank 的注释更多细节。
  • 如果有锁定的文件会怎样?
  • 符号链接是否需要特殊处理(以避免无限循环)?
  • 如何输出错误文件的完整路径名?

这个答案是一个起点,而不是一个完整且强大的计算目录大小的程序。 如果您需要更多帮助,请阅读 du 程序的源代码。

Based on Jim Plank's example to get you started:

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

int main( int argc, char **argv ) {
  DIR *d = opendir( "." );

  if( d == NULL ) {
    fprintf( stderr, "Cannot open current working directory\n" );
    return 1;
  }

  struct dirent *de;
  struct stat buf;
  int total_size = 0;

  for( de = readdir( d ); de != NULL; de = readdir( d ) ) {
    int exists = stat( de->d_name, &buf );

    if( exists < 0 ) {
      fprintf( stderr, "Cannot read file statistics for %s\n", de->d_name );
    } else {
      total_size += buf.st_size;
    }
  }

  closedir( d );
  printf( "%d\n", total_size );

  return 0;
}

Notes, considerations, and questions for the reader:

  • This is example is incomplete. See Plank's notes for more details.
  • What happens if there are locked files?
  • Do symbolic links need special handling (to avoid infinite loops)?
  • How would you output the full path name for erroneous files?

This answer is a starting point, not a complete and robust program to calculate directory sizes. If you need more help, read the source code for the du program.

想你的星星会说话 2024-08-03 04:54:52

您需要 stat() 当前目录和子目录中的所有文件并将它们相加。

考虑为此使用递归算法。

You need to stat() all the files in the current directory and sub directories and add them up.

Consider using a recursive algorithm for this.

以可爱出名 2024-08-03 04:54:52

我想这个解决方案对于那些仍然可能遇到问题的人来说可能会有用。

这是为模仿 Linux du 程序而编写的函数。 它递归地遍历所有目录并累加文件大小。

注意,这个函数仍然不完整,因为它在硬链接上的行为不正确。 人们应该添加一个容器来存储指向同一 inode 实体的文件描述符,并使用它来消除同一文件的多个计数。 lstat() 用于处理符号链接(又名软链接),硬链接是这里的一个问题

size_t countDiskUsage(const char* pathname)
{
  if (pathname == NULL) {
    printf("Erorr: pathname is NULL\n");
  }

  struct stat stats;

  if (lstat(pathname, &stats) == 0) {
    if (S_ISREG(stats.st_mode)){
      return stats.st_size;
    }
  } else {
    perror("lstat\n");
  }

  DIR* dir = opendir(pathname);

  if (dir == NULL) {
    perror("Error");
    return 0;
  }

  struct dirent *dirEntry;
  size_t totalSize = 4096;

  for (dirEntry = readdir(dir); dirEntry != NULL; dirEntry =   readdir(dir)) {
    long pathLength = sizeof(char) * (strlen(pathname) + strlen(dirEntry->d_name) + 2);
    char* name = (char*)malloc(pathLength);
    strcpy(name, pathname);
    strcpy(name + strlen(pathname), "/");
    strcpy(name + strlen(pathname) + 1, dirEntry->d_name);

    if (dirEntry->d_type == DT_DIR) {
      if (strcmp(dirEntry->d_name, ".") != 0 && strcmp(dirEntry->d_name, "..") != 0) {
        totalSize += countDiskUsage(name);
      }
    } else {
      int status = lstat(name, &stats);
      if (status == 0) {
        totalSize += stats.st_size;
      } else {
        perror("lstat\n");
      }
    }
    free(name);
  }

  closedir(dir);

  return totalSize;
}

I guess the solution may be useful for those who still may encounter the problem.

Here's the function that was written to imitate linux du program. It recursively goes through all directories and adds up file sizes.

Note, that this function is still incomplete, since it behaves incorrectly on hard links. One should add a container to store file descriptors that point to the same inode entity and use that to get rid of multiple counts of the very same file. lstat() is used to handle symlinks (aka soft links), hard links is an issue here.

size_t countDiskUsage(const char* pathname)
{
  if (pathname == NULL) {
    printf("Erorr: pathname is NULL\n");
  }

  struct stat stats;

  if (lstat(pathname, &stats) == 0) {
    if (S_ISREG(stats.st_mode)){
      return stats.st_size;
    }
  } else {
    perror("lstat\n");
  }

  DIR* dir = opendir(pathname);

  if (dir == NULL) {
    perror("Error");
    return 0;
  }

  struct dirent *dirEntry;
  size_t totalSize = 4096;

  for (dirEntry = readdir(dir); dirEntry != NULL; dirEntry =   readdir(dir)) {
    long pathLength = sizeof(char) * (strlen(pathname) + strlen(dirEntry->d_name) + 2);
    char* name = (char*)malloc(pathLength);
    strcpy(name, pathname);
    strcpy(name + strlen(pathname), "/");
    strcpy(name + strlen(pathname) + 1, dirEntry->d_name);

    if (dirEntry->d_type == DT_DIR) {
      if (strcmp(dirEntry->d_name, ".") != 0 && strcmp(dirEntry->d_name, "..") != 0) {
        totalSize += countDiskUsage(name);
      }
    } else {
      int status = lstat(name, &stats);
      if (status == 0) {
        totalSize += stats.st_size;
      } else {
        perror("lstat\n");
      }
    }
    free(name);
  }

  closedir(dir);

  return totalSize;
}
天涯沦落人 2024-08-03 04:54:52

如果您不想使用 'system',但可以使用 'pipe''fork''execlp ''du',您可以构建一个管道,分叉一个新进程,重定向管道中子进程的 'STDOUT',执行 'du' 在子级中,并在父级中读取结果。 示例代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(void) {
  int pfd[2], n;
  char str[1000];

  if (pipe(pfd) < 0) {
    printf("Oups, pipe failed.  Exiting\n");
    exit(-1);
  }

  n = fork();

  if (n < 0) {
    printf("Oups, fork failed.  Exiting\n");
    exit(-2);
  } else if (n == 0) {
    close(pfd[0]);

    dup2(pfd[1], 1);
    close(pfd[1]);

    execlp("du", "du", "-sh", "/tmp", (char *) 0);
    printf("Oups, execlp failed.  Exiting\n"); /* This will be read by the  parent. */
    exit(-1); /* To avoid problem if execlp fails, especially if in a loop. */
  } else {
    close(pfd[1]);

    n = read(pfd[0], str, 1000); /* Should be done in a loop until read return 0, but I am lazy. */
    str[n] = '\0';

    close(pfd[0]);
    wait(&n); /* To avoid the zombie process. */

    if (n == 0) {
       printf("%s", str);
    } else {
       printf("Oups, du or execlp failed.\n");
    }
  }
}

If you do not want to use 'system', but are ok to use 'pipe', 'fork', 'execlp' and 'du', you could build a pipe, fork a new process, redirect 'STDOUT' of the child in the pipe, exec 'du' in the child, and read the result in the parent. A sample code would be:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(void) {
  int pfd[2], n;
  char str[1000];

  if (pipe(pfd) < 0) {
    printf("Oups, pipe failed.  Exiting\n");
    exit(-1);
  }

  n = fork();

  if (n < 0) {
    printf("Oups, fork failed.  Exiting\n");
    exit(-2);
  } else if (n == 0) {
    close(pfd[0]);

    dup2(pfd[1], 1);
    close(pfd[1]);

    execlp("du", "du", "-sh", "/tmp", (char *) 0);
    printf("Oups, execlp failed.  Exiting\n"); /* This will be read by the  parent. */
    exit(-1); /* To avoid problem if execlp fails, especially if in a loop. */
  } else {
    close(pfd[1]);

    n = read(pfd[0], str, 1000); /* Should be done in a loop until read return 0, but I am lazy. */
    str[n] = '\0';

    close(pfd[0]);
    wait(&n); /* To avoid the zombie process. */

    if (n == 0) {
       printf("%s", str);
    } else {
       printf("Oups, du or execlp failed.\n");
    }
  }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文