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

使用fgets读取文件首行时始终出现3个无效字符的技术问题

解决读取文本文件首行出现乱码字符的问题

兄弟,你这遇到的是典型的**UTF-8字节顺序标记(BOM)**的坑!那些看起来诡异的(调试控制台)或者∩╗┐(终端),本质是文件开头的三个特殊字节0xEF 0xBB 0xBF——也就是UTF-8的BOM——被你的C代码当成普通ASCII字符解析后显示出来的乱码。

为啥会出现这问题?

  • 有些编辑器(比如Windows自带的记事本)在保存UTF-8格式文件时,会自动在文件最开头加上这三个字节作为标识,但UTF-8本身其实不需要BOM
  • 你用fgets读取时,C标准库的默认文本模式不会自动识别并跳过这个BOM,所以直接把它当成了文本内容的一部分读进来
  • 删掉首行后,BOM还是在文件最开头,所以新的首行自然也带着它;而加了空行后,BOM被包含在空行里,后续的有效内容就不受影响了

给你几个解决办法:

1. 直接去掉文件里的BOM

用支持编码设置的编辑器重新保存文件就行:

  • VS Code:点击右下角的编码标识(比如显示“UTF-8”),选择「通过编码保存」,然后选「UTF-8」(别选带BOM的选项)
  • Notepad++:顶部菜单「编码」→「转为UTF-8无BOM格式」

2. 在代码里自动跳过BOM

如果没法修改文件,或者需要兼容带BOM的文件,可以在读取第一行时检测并跳过这三个字节:

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

#define LINELENGTH 256

int main() {
    FILE *stream = fopen("your_input_file.txt", "r");
    if (!stream) {
        perror("Failed to open file");
        return 1;
    }

    char line[LINELENGTH];
    int is_first_line = 1;

    while (fgets(line, LINELENGTH, stream) != NULL) {
        if (is_first_line) {
            // 检查开头是否是UTF-8 BOM
            if (strlen(line) >= 3 && 
                (unsigned char)line[0] == 0xEF && 
                (unsigned char)line[1] == 0xBB && 
                (unsigned char)line[2] == 0xBF) {
                // 把BOM后的内容移到开头,去掉BOM
                memmove(line, line + 3, strlen(line) - 2);
            }
            is_first_line = 0;
        }
        // 这里处理你的业务逻辑,比如打印或者解析
        printf("%s", line);
    }

    fclose(stream);
    return 0;
}

这里用memmove而不是strcpy是因为源和目标内存区域有重叠,memmove能安全处理这种情况。

3. 二进制模式读取(不推荐,除非必要)

如果需要更底层的控制,可以用二进制模式打开文件(fopen的第二个参数用"rb"),手动检测BOM后再处理文本,但这种方式需要自己处理Windows下的\r\n换行符转\n,一般没必要这么折腾。

后续预防

  • 以后保存文本文件时,记得选无BOM的UTF-8格式
  • 如果是自己写程序生成文件,确保输出时不要添加UTF-8 BOM

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 17:37:35