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

高级I/O版chunk.c改低级系统调用后分片异常,求修复

定位并修复低级系统调用版文件拆分程序的问题

常见问题根源

低级系统调用(如read/write/open)是无缓冲的,和高级I/O(fgets/fprintf)的行处理逻辑完全不同,只生成第一个分片通常是以下原因:

  • 未处理不完整行:一次read可能只读到半行,直接计数换行符会导致后续行统计错误,误以为文件已结束。
  • 分片切换逻辑错误:写完第一个分片后未关闭当前文件描述符,也未正确打开下一个分片文件。
  • 循环终止条件错误:没有处理read返回部分数据(非EOF)的情况,提前退出循环。

修复后的完整实现

#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#define BUFFER_SIZE 4096
#define PART_FMT "part-%02d"

int main(int argc, char *argv[]) {
    if (argc != 3) {
        fprintf(stderr, "Usage: %s <input-file> <lines-per-part>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    const char *input_path = argv[1];
    int lines_per_part = atoi(argv[2]);
    if (lines_per_part <= 0) {
        fprintf(stderr, "Invalid lines per part: %d\n", lines_per_part);
        exit(EXIT_FAILURE);
    }

    int input_fd = open(input_path, O_RDONLY);
    if (input_fd == -1) {
        perror("Failed to open input file");
        exit(EXIT_FAILURE);
    }

    int part_num = 0;
    int line_count = 0;
    int output_fd = -1;
    char buffer[BUFFER_SIZE];
    ssize_t bytes_read;
    char *buf_ptr, *newline_ptr;
    size_t total_bytes, remain_bytes = 0;

    // 初始化第一个分片文件
    char part_path[256];
    snprintf(part_path, sizeof(part_path), PART_FMT, part_num);
    output_fd = open(part_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (output_fd == -1) {
        perror("Failed to open first part file");
        close(input_fd);
        exit(EXIT_FAILURE);
    }

    while ((bytes_read = read(input_fd, buffer + remain_bytes, BUFFER_SIZE - remain_bytes)) > 0) {
        total_bytes = bytes_read + remain_bytes;
        buf_ptr = buffer;

        while (buf_ptr < buffer + total_bytes) {
            newline_ptr = memchr(buf_ptr, '\n', buffer + total_bytes - buf_ptr);
            if (!newline_ptr) {
                // 缓存未处理的半行数据到缓冲区头部
                memmove(buffer, buf_ptr, buffer + total_bytes - buf_ptr);
                remain_bytes = buffer + total_bytes - buf_ptr;
                break;
            }

            // 写入当前完整行
            size_t line_len = newline_ptr - buf_ptr + 1;
            if (write(output_fd, buf_ptr, line_len) != line_len) {
                perror("Write to part file failed");
                close(input_fd);
                close(output_fd);
                exit(EXIT_FAILURE);
            }

            line_count++;
            buf_ptr = newline_ptr + 1;

            // 达到行数阈值,切换分片
            if (line_count == lines_per_part) {
                close(output_fd);
                part_num++;
                line_count = 0;

                snprintf(part_path, sizeof(part_path), PART_FMT, part_num);
                output_fd = open(part_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
                if (output_fd == -1) {
                    perror("Open new part file failed");
                    close(input_fd);
                    exit(EXIT_FAILURE);
                }
            }
        }

        // 缓冲区已完全处理,重置剩余字节数
        if (buf_ptr >= buffer + total_bytes) {
            remain_bytes = 0;
        }
    }

    // 处理文件末尾的剩余数据(无换行符的内容)
    if (remain_bytes > 0 && output_fd != -1) {
        if (write(output_fd, buffer, remain_bytes) != remain_bytes) {
            perror("Write remaining data failed");
            close(input_fd);
            close(output_fd);
            exit(EXIT_FAILURE);
        }
    }

    // 清理所有文件描述符
    close(input_fd);
    if (output_fd != -1) {
        close(output_fd);
    }

    return EXIT_SUCCESS;
}

关键修复点说明

  • 半行数据缓存:每次读取后如果找不到完整换行符,将剩余数据移到缓冲区头部,下次读取时拼接,保证行统计准确。
  • 分片切换逻辑:达到指定行数后,立即关闭当前输出文件,重新打开新的分片文件,同时重置计数器和分片编号。
  • 部分读取处理:循环调用read直到返回0(EOF),确保读取完所有数据,避免提前退出。
  • 资源安全:所有打开的文件描述符都在程序结束前关闭,避免资源泄漏。

内容的提问来源于stack exchange,提问作者springbook

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 04:54:53