基于ftw与进程的问题:编写多进程C程序按文件大小排序目录文件
C程序:父子进程配合管道实现目录文件按大小排序
没问题,我来给你写一个完全符合要求的C程序——用父子进程(不是线程)配合管道来实现目录及子目录下普通文件的按大小排序功能。先给你捋清楚核心逻辑:父进程先创建管道,然后fork出子进程;子进程负责递归扫描目标目录,找到普通文件就获取它的大小和路径,通过管道把这些信息传给父进程;父进程收集完所有文件数据后,按大小升序排序再输出结果。
完整代码实现
#include <stdio.h> #include <stdlib.h> #include <dirent.h> #include <sys/stat.h> #include <unistd.h> #include <string.h> #include <sys/wait.h> #include <limits.h> // 存储文件大小和路径的结构体 typedef struct { long size; char path[PATH_MAX]; } FileInfo; // 子进程递归扫描目录的函数 void scan_directory(const char *dir, int pipe_write_fd) { DIR *dp = opendir(dir); if (!dp) { perror("opendir failed"); return; } struct dirent *entry; while ((entry = readdir(dp)) != NULL) { // 跳过当前目录和上级目录 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { continue; } // 拼接完整路径 char full_path[PATH_MAX]; snprintf(full_path, sizeof(full_path), "%s/%s", dir, entry->d_name); struct stat stat_buf; if (lstat(full_path, &stat_buf) == -1) { perror("lstat failed"); continue; } // 如果是普通文件,发送信息到管道 if (S_ISREG(stat_buf.st_mode)) { FileInfo info; info.size = stat_buf.st_size; strncpy(info.path, full_path, sizeof(info.path) - 1); info.path[sizeof(info.path) - 1] = '\0'; // 确保字符串终止 if (write(pipe_write_fd, &info, sizeof(info)) == -1) { perror("write to pipe failed"); closedir(dp); return; } } // 如果是目录,递归扫描 else if (S_ISDIR(stat_buf.st_mode)) { scan_directory(full_path, pipe_write_fd); } } closedir(dp); } // qsort的比较函数:按文件大小升序排序 int compare_files(const void *a, const void *b) { const FileInfo *file_a = (const FileInfo *)a; const FileInfo *file_b = (const FileInfo *)b; return (file_a->size > file_b->size) - (file_a->size < file_b->size); } int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "Usage: %s <directory>\n", argv[0]); exit(EXIT_FAILURE); } int pipe_fd[2]; // 创建管道 if (pipe(pipe_fd) == -1) { perror("pipe failed"); exit(EXIT_FAILURE); } pid_t pid = fork(); if (pid == -1) { perror("fork failed"); exit(EXIT_FAILURE); } if (pid == 0) { // 子进程:关闭管道读端,只保留写端 close(pipe_fd[0]); // 开始扫描目录 scan_directory(argv[1], pipe_fd[1]); // 写完后关闭写端 close(pipe_fd[1]); exit(EXIT_SUCCESS); } else { // 父进程:关闭管道写端,只保留读端 close(pipe_fd[1]); FileInfo *files = NULL; size_t count = 0; size_t capacity = 4; // 初始容量,动态扩容 // 从管道读取子进程发送的文件信息 FileInfo temp; ssize_t bytes_read; while ((bytes_read = read(pipe_fd[0], &temp, sizeof(temp))) > 0) { // 动态扩容数组 if (count >= capacity) { capacity *= 2; FileInfo *new_files = realloc(files, capacity * sizeof(FileInfo)); if (!new_files) { perror("realloc failed"); free(files); close(pipe_fd[0]); wait(NULL); exit(EXIT_FAILURE); } files = new_files; } files[count++] = temp; } if (bytes_read == -1) { perror("read from pipe failed"); free(files); close(pipe_fd[0]); wait(NULL); exit(EXIT_FAILURE); } // 关闭管道读端 close(pipe_fd[0]); // 等待子进程结束 wait(NULL); // 按文件大小排序 qsort(files, count, sizeof(FileInfo), compare_files); // 输出排序结果 printf("Files sorted by size (ascending):\n"); for (size_t i = 0; i < count; i++) { printf("%10ld bytes: %s\n", files[i].size, files[i].path); } free(files); exit(EXIT_SUCCESS); } }
关键细节说明
- 管道通信机制:父进程通过
pipe()创建管道,得到读、写两个文件描述符。子进程关闭读端只写数据,父进程关闭写端只读数据,实现了父子进程的单向安全通信。 - 递归目录扫描:
scan_directory()函数用opendir()打开目录,遍历每个条目时跳过.和..(避免无限递归),通过lstat()判断文件类型:普通文件就打包成FileInfo结构体写入管道;目录则递归调用自身继续扫描。 - 动态内存管理:父进程用动态扩容的数组存储文件信息,初始容量设为4,当数据量超过容量时自动翻倍扩容,避免内存浪费或不足。
- 排序实现:借助标准库的
qsort()函数,配合自定义的compare_files()比较函数,实现按文件大小的升序排序。 - 错误处理:所有关键系统调用(如
pipe()、fork()、opendir()、read()、write())都添加了错误检查,确保程序在异常情况下能给出清晰提示并安全退出。
编译与运行
用gcc编译程序:
gcc file_sort.c -o file_sort
运行时指定要扫描的目标目录:
./file_sort /path/to/your/target/directory
内容的提问来源于stack exchange,提问作者N Shah
相关产品推荐
相关产品推荐

