fputs与fwrite安全性对比及文件子串写入安全实现咨询
更安全的文件写入方案及fputs vs fwrite对比
首先,咱们先拆解你现有代码里的潜在问题,再给出改进方案,最后聊聊fputs和fwrite的安全性差异。
现有代码的风险点
你的代码里fputs(strstr(line, p_name), fp2)存在几个值得注意的问题:
- 未检查写入结果:fputs写入失败时会返回EOF,但你没有做任何检查——如果磁盘满了、文件被意外关闭,你根本不知道写入出问题了。
- 写入内容超出预期:strstr返回的是子串在line里的起始指针,fputs会从这个指针一直写到字符串末尾('\0'),也就是把该行中从子串开始到结尾的所有内容都写进去了,而不是仅写入你要找的子串本身(除非你的需求就是这样,但通常查找子串是要单独写入子串)。
- 边界情况处理缺失:比如如果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
相关产品推荐
相关产品推荐

