向文件添加字符串结束符致损坏?Shell注释处理实现遇阻
解决Shell注释处理中的文件损坏问题
嘿,我来帮你搞定这个注释处理的坑!你遇到的文件损坏问题,核心原因是只替换#为\0但没有真正截断文件,加上文件指针的位置没处理对,导致原文件后面的内容还留在磁盘上,看起来就像是"损坏"了。
先拆解你的需求:
- 把文件中非转义的
#(也就是前面没有$的#)作为注释开头,截断后面所有内容 - 对于
$#这种情况,#是普通字符,不能当作注释处理
原代码的问题分析
- 文件修改方式错误:你用
r+模式打开文件后,只把#替换成\0,但文件的实际大小并没有改变——后面的$#789依然存在于文件中。虽然读取时会在\0处停止,但磁盘上的文件还是完整长度,这就导致文件行为不符合预期。 - 指针位置处理失误:
fgetc读取字符后,文件指针会自动移动到下一个字符的位置。这时候如果你直接写\0,会覆盖下一个字符,而不是当前的#,逻辑完全错了。 - 转义逻辑不完整:原代码里的
$处理只写了一半,没有正确跳过转义后的字符,也没处理边界情况(比如$是文件最后一个字符)。
修复后的代码实现
下面是调整后的removeComments函数,用截断文件的方式实现真正的注释截断,同时正确处理转义的$:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> // 用于ftruncate系统调用 int removeComments(char* fileName) { FILE* myfile = fopen(fileName, "r+"); if (myfile == NULL) { fprintf(stderr, "cannot open %s\n", fileName); return -1; // 用return替代exit,让函数更灵活 } long comment_pos = -1; // 记录注释开始的位置 int current_char; long file_offset = 0; while ((current_char = fgetc(myfile)) != EOF) { if (current_char == '$') { // 遇到转义符$,跳过下一个字符(不视为注释) current_char = fgetc(myfile); if (current_char == EOF) break; // 处理$在文件末尾的情况 file_offset += 2; } else if (current_char == '#') { // 找到非转义的#,记录位置并退出循环 comment_pos = file_offset; break; } file_offset++; } if (comment_pos != -1) { // 移动文件指针到注释开始的位置 fseek(myfile, comment_pos, SEEK_SET); // 截断文件,真正删除注释后的所有内容 if (ftruncate(fileno(myfile), comment_pos) == -1) { fprintf(stderr, "failed to truncate %s\n", fileName); fclose(myfile); return -1; } // 如果你需要在截断处写入\0(可选,一般不需要): // fputc('\0', myfile); // 注意:写入\0后要把截断位置改成comment_pos + 1 } fclose(myfile); return 0; }
关键修复点说明
- 用
ftruncate截断文件:这是实现"截断"的核心——直接告诉操作系统把文件的长度缩短到注释开始的位置,彻底删除后面的内容,而不是只写一个\0糊弄过去。 - 正确处理文件指针:用
file_offset跟踪当前读取的位置,找到#后通过fseek准确定位到注释开头,再执行截断。 - 完整的转义逻辑:遇到
$时,直接跳过下一个字符,确保$后面的#不会被当作注释处理,同时处理了$在文件末尾的边界情况。
测试你的示例文件
对于你的output文件内容123 #456 $#789,这个函数会找到第一个非转义的#(在123 之后),然后截断文件到这个位置,最终文件内容就是123 ,完全符合你的需求。
内容的提问来源于stack exchange,提问作者Lazarus
相关产品推荐
相关产品推荐

