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

fputs与fwrite安全性对比及文件子串写入安全实现咨询

更安全的文件写入方案及fputs vs fwrite对比

首先,咱们先拆解你现有代码里的潜在问题,再给出改进方案,最后聊聊fputs和fwrite的安全性差异。

现有代码的风险点

你的代码里fputs(strstr(line, p_name), fp2)存在几个值得注意的问题:

  1. 未检查写入结果:fputs写入失败时会返回EOF,但你没有做任何检查——如果磁盘满了、文件被意外关闭,你根本不知道写入出问题了。
  2. 写入内容超出预期:strstr返回的是子串在line里的起始指针,fputs会从这个指针一直写到字符串末尾('\0'),也就是把该行中从子串开始到结尾的所有内容都写进去了,而不是仅写入你要找的子串本身(除非你的需求就是这样,但通常查找子串是要单独写入子串)。
  3. 边界情况处理缺失:比如如果p_name是空字符串(虽然你可能不会遇到),strstr会返回line的起始地址,导致整行被写入,这显然不符合预期。

更安全的改进方案

要解决这些问题,核心是精确控制写入的内容长度,同时严格检查所有IO操作的返回值。这里用fwrite来实现,因为它能指定写入的字节数,避免多余内容,也更安全。

修改后的代码示例:

#include <string.h>
#include <stdio.h>

#define MAX_LINE_LEN 1024

int main() {
    FILE *fp1 = fopen("input.txt", "r");
    FILE *fp2 = fopen("output.txt", "w");
    const char *p_name = "your_target_substring";
    int pname_count = 0;
    char line[MAX_LINE_LEN];

    // 先检查文件是否成功打开
    if (!fp1 || !fp2) {
        perror("Failed to open file");
        return 1;
    }

    while (fgets(line, MAX_LINE_LEN, fp1) != NULL) {
        if (pname_count < 1) {
            char *substr_ptr = strstr(line, p_name);
            if (substr_ptr != NULL) {
                pname_count++;
                // 拿到子串的实际长度
                size_t substr_len = strlen(p_name);
                // 精确写入子串内容
                size_t written = fwrite(substr_ptr, 1, substr_len, fp2);
                // 检查写入是否成功
                if (written != substr_len) {
                    perror("Failed to write substring");
                    // 错误处理:关闭文件后退出
                    fclose(fp1);
                    fclose(fp2);
                    return 1;
                }
                // 如果需要换行,可以手动加:fputc('\n', fp2);
                continue;
            }
        }
        // 你的剩余代码
    }

    // 检查fgets是否因为读取错误退出
    if (ferror(fp1)) {
        perror("Error reading input file");
        fclose(fp1);
        fclose(fp2);
        return 1;
    }

    // 关闭文件也要检查?其实fclose失败通常是写入缓冲区时出问题,也可以处理
    if (fclose(fp1) != 0 || fclose(fp2) != 0) {
        perror("Failed to close file");
        return 1;
    }

    return 0;
}

fputs与fwrite的安全性差异

咱们直接对比两者的核心特点和风险:

  • fputs:

    • 专门用于写入以'\0'结尾的字符串,会自动忽略终止符(不写入'\0'到文件)。
    • 风险:如果传入的指针指向的不是合法的'\0'终止字符串,会触发缓冲区溢出,程序会一直读取内存直到找到'\0',这属于未定义行为(可能崩溃、写入垃圾数据)。
    • 局限性:无法控制写入长度,只能写到字符串末尾,如果你只需要写入部分内容,它做不到。
    • 必须检查返回值:成功返回非负值,失败返回EOF,不检查就无法感知写入错误。
  • fwrite:

    • 通用的二进制写入函数,需要你明确指定元素大小、元素个数,总写入字节数是size * count。
    • 安全性优势:完全由你控制写入的字节数,不管数据有没有'\0'终止符,都不会出现溢出问题,也不会写入多余内容。
    • 灵活性:既可以写文本,也可以写二进制数据(比如图片、音频),适用场景更广。
    • 同样要检查返回值:返回成功写入的元素个数,如果小于你指定的count,说明写入失败。

额外的安全建议

  • 所有文件操作(打开、读取、写入、关闭)都要检查返回值,IO操作是程序中最容易出问题的环节之一。
  • 如果你的场景需要处理超长行,MAX_LINE_LEN固定大小可能不够,考虑用动态内存分配(比如getline函数,不过注意它是POSIX标准)。
  • 如果你需要写入的子串包含特殊字符或二进制数据,fwrite是唯一安全的选择,因为fputs会把'\0'当作终止符。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 10:24:52