如何用C++去除记事本.txt文件中的BOM以实现正常读取?
完全没问题!针对你遇到的BOM导致读取异常的问题,我给你两个实用的C++解决方案——一个是直接物理删除文件中的BOM(一次性搞定多文件,不用手动改),另一个是读取时动态跳过BOM(类似Java里PushbackInputStream的思路,不用修改原文件),都不需要额外下载软件,纯代码就能实现,完美匹配你的需求。
方案1:物理删除文件中的UTF-8 BOM
首先明确:UTF-8的BOM是开头3个字节EF BB BF(你提到的8个字符大概率是这3个字节被工具显示成了异常字符)。下面的代码会自动检测文件开头是否有BOM,有就把后续内容覆盖原文件,彻底移除BOM:
#include <fstream> #include <vector> #include <cstdint> #include <filesystem> // C++17及以上支持,用于文件遍历与替换 using namespace std; namespace fs = filesystem; void removeBOM(const string& filePath) { // 以二进制模式打开文件,避免文本模式的换行转换干扰字节结构 ifstream inFile(filePath, ios::binary); if (!inFile) { cerr << "无法打开文件:" << filePath << endl; return; } // 读取前3个字节,判断是否为UTF-8 BOM uint8_t bom[3]; inFile.read(reinterpret_cast<char*>(bom), 3); bool hasBOM = (bom[0] == 0xEF && bom[1] == 0xBB && bom[2] == 0xBF); // 无BOM则回到文件开头,有BOM则跳过这3个字节 if (!hasBOM) { inFile.seekg(0); } // 读取剩余所有文件内容 vector<char> content((istreambuf_iterator<char>(inFile)), istreambuf_iterator<char>()); inFile.close(); // 以二进制模式覆盖写入原文件 ofstream outFile(filePath, ios::binary | ios::trunc); if (!outFile) { cerr << "无法写入文件:" << filePath << endl; return; } outFile.write(content.data(), content.size()); outFile.close(); cout << "处理完成:" << filePath << (hasBOM ? "(已移除BOM)" : "(无BOM)") << endl; } // 批量处理指定文件夹下的所有.txt文件 void batchRemoveBOM(const string& folderPath) { for (const auto& entry : fs::directory_iterator(folderPath)) { if (entry.is_regular_file() && entry.path().extension() == ".txt") { removeBOM(entry.path().string()); } } } int main() { // 单个文件处理示例 // removeBOM("test.txt"); // 批量处理示例(替换为你的txt文件夹路径) batchRemoveBOM("./your_txt_folder"); return 0; }
注意事项:
- 必须用二进制模式读写,防止文本模式下的换行符转换破坏BOM字节
- 若使用C++17以下标准,可以用
_findfirst/_findnext替代filesystem实现文件夹遍历 - 批量处理前建议备份文件,避免意外情况
方案2:读取时跳过BOM(类似PushbackInputStream思路)
如果不想修改原文件,只是在读取阶段跳过BOM,可以用类似Java PushbackInputStream的逻辑:先预读几个字节判断是否为BOM,是就跳过,否则把预读内容“推回”文件流,继续正常读取:
#include <fstream> #include <string> #include <cstdint> using namespace std; string readFileWithoutBOM(const string& filePath) { ifstream inFile(filePath, ios::binary); if (!inFile) { cerr << "无法打开文件:" << filePath << endl; return ""; } uint8_t bom[3]; inFile.read(reinterpret_cast<char*>(bom), 3); bool hasBOM = (bom[0] == 0xEF && bom[1] == 0xBB && bom[2] == 0xBF); // 无BOM则将文件指针移回开头,相当于没预读过这些字节 if (!hasBOM) { inFile.seekg(0); } // 读取剩余所有内容(已跳过BOM) string content((istreambuf_iterator<char>(inFile)), istreambuf_iterator<char>()); inFile.close(); return content; } int main() { string content = readFileWithoutBOM("test.txt"); // 这里可以直接处理content,已自动跳过BOM,不会出现读取异常 cout << content << endl; return 0; }
说明:
- 核心是通过
seekg(0)实现“回退”,和PushbackInputStream的预读-判断-回退逻辑完全一致 - 读取后的内容是纯文本,后续用常规字符串处理或写入其他文件都不会有BOM问题
不管选哪个方案,处理后用记事本打开都完全正常,不需要修改记事本的任何设置,也不用额外工具。批量处理多文件的话,方案1能一次性解决根源问题,后续读取再也不用操心BOM的事。
内容的提问来源于stack exchange,提问作者Inertial Ignorance
相关产品推荐
相关产品推荐

