You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 08:04:25