C语言批量创建千级文本文件的效率与可移植性优化咨询
现有代码的隐患
你现在的代码能跑通1000个文件的场景,但藏了不少问题,扩量或者换系统很容易崩:
- 缓冲区溢出风险:存数字的
snum只开了5字节,数字到10000的时候是5位十进制数,算上字符串末尾的\0结束符至少要6字节,现在跑1000个文件刚好卡4位数字的边界,扩到10000直接内存越界。 - 无任何错误处理:
fopen如果因为权限不足、磁盘满、路径非法返回空指针,后面的fprintf直接解引用空指针会让程序当场崩溃,跨系统跑的时候Windows和类Unix的默认权限逻辑不一样,没错误处理换环境大概率出问题。 - 冗余字符串操作太多:每次循环都要先重置前缀、再三次拼接字符串,
strcat每次都要从头扫到字符串末尾找结束位,平白多了很多没必要的性能损耗。
基础优化方案(兼容跨平台、运行效率更高)
优化核心就是砍掉冗余逻辑、补全容错、留足安全余量,全程只用C标准库接口,保证Windows、Linux、macOS不管32位还是64位环境都能直接编译运行,不需要改代码:
- 提前把固定的文件名前缀、后缀预存到缓冲区,不用每次循环重复拷贝重置
- 算好前缀的固定偏移,直接在对应位置写数字,省掉
strcat扫字符串的开销 - 缓冲区留足冗余,文件名缓冲区开256字节(覆盖所有主流系统的单文件名长度限制),数字存储位置留足够长度,哪怕扩到9位数的文件量都不会溢出
- 补全IO错误判断,出错了打日志跳过,不会直接崩溃
优化后的代码:
#include <stdio.h> #include <string.h> #include <errno.h> int main(void) { const int total_files = 1000; const char *prefix = "file_no_"; const char *suffix = ".txt"; char filename[256]; const int prefix_len = (int)strlen(prefix); const int suffix_len = (int)strlen(suffix); // 预存固定前缀 memcpy(filename, prefix, prefix_len); for (int i = 1; i <= total_files; i++) { // 直接在前缀后面写数字,返回值就是数字的字符串长度 int num_len = sprintf(filename + prefix_len, "%d", i); // 把后缀拼到数字后面,带上字符串结束符 memcpy(filename + prefix_len + num_len, suffix, suffix_len + 1); FILE *fp = fopen(filename, "w"); if (fp == NULL) { fprintf(stderr, "创建文件 %s 失败:%s\n", filename, strerror(errno)); continue; } fprintf(fp, "This is file no %d", i); fclose(fp); } return 0; }
这个版本比原代码效率高很多,字符串操作的冗余基本砍完了,跑1000个文件的耗时基本只剩磁盘IO本身的时间,没有多余的CPU开销。
10000个及更大规模文件的优化思路
如果只是10000个文件,上面的优化版代码完全够用,普通机械硬盘上单线程跑也就1-2秒跑完,不需要搞多余的花活。如果后续要扩到十万、百万级文件量,可以再做几个调整,实际收益很高:
- 文件名补零对齐:数字用
%05d(对应万级规模)格式化,比如1输出成00001,10000输出成10000,所有文件名长度一致,文件系统存元数据的时候排列更整齐,创建、遍历速度都会有提升,后续排序的时候也不会出现字符串排序把10排在2前面的问题。 - 分目录存储:不管是NTFS、ext4还是APFS,单个目录下存超过1万个文件的时候,目录项的查找性能会明显下跌。可以按编号分子目录,比如每1000个文件放一个子目录,比如
0-999、1000-1999,不仅后续找文件方便,创建文件时的文件系统开销也会低很多。 - 适当调大IO缓冲区:默认
fopen给的缓冲区一般是4-8KB,批量写小文件的时候可以用setvbuf把单文件的IO缓冲区开到64KB,能减少很多内核态和用户态的切换次数,IO等待时间能降30%左右。 - 提前做前置检查:跑循环之前先确认目标目录有写入权限、磁盘剩余空间足够,不要等跑到一半因为磁盘满、权限掉了中断,重跑反而浪费时间。
别为了追速度去调用系统专属的异步IO、绕开页缓存的接口,万级甚至十万级小文件的场景下,标准C库的IO效率已经足够高,用系统专属API反而会破坏跨平台兼容性,实际收益极低。
内容的提问来源于stack exchange,提问作者user9026
相关产品推荐
相关产品推荐

