如何在文件中查找Matroska Segment EBML字节序列?我的方法是否有误?
你的代码存在多个关键问题,导致无法匹配目标字节序列
咱们一步步拆解问题所在,再给出正确的实现方式:
核心错误点
- 目标序列完全不匹配:你要找的是十六进制
0x18 0x53 0x80 0x67(对应十进制24、83、128、103),但代码里的判断条件是检查buffer[0]==1、buffer[1]==8等,这和目标序列完全无关,相当于在找另一个完全不同的字节串,肯定找不到结果。 - 数组越界访问:你定义的
buffer是char[8],数组索引从0开始,最大只能访问buffer[7],但代码里用到了buffer[8],这会触发未定义行为,程序可能崩溃或输出错误结果。 - 读取逻辑错误:每次循环只读取1个字节到
buffer[0],然后去检查buffer[1]到buffer[8]的内容——这些位置根本没有被新读取的数据填充,都是数组初始化后的垃圾值,自然不可能匹配成功。 - 循环边界问题:当
i接近文件末尾时,剩余字节不足4个,此时强行检查后续字节会导致读取超出文件范围,同样引发未定义行为。
正确的实现思路
要查找连续的4字节序列,推荐用滑动窗口的方式:逐个读取字节,维护最近的3个字节,每次新读一个字节后,就把这4个字节(前3个+当前)和目标序列对比。或者一次性读取整个文件到缓冲区,然后在缓冲区里查找(适合小文件)。
修正后的代码示例(滑动窗口方式)
#include <iostream> #include <fstream> int main() { std::ifstream is("your_file_path", std::ios::binary); if (!is.is_open()) { std::cerr << "Failed to open file!" << std::endl; return 1; } // 目标字节序列:0x18, 0x53, 0x80, 0x67 const unsigned char target[] = {0x18, 0x53, 0x80, 0x67}; const int target_len = sizeof(target) / sizeof(target[0]); // 滑动窗口缓冲区,保存最近的target_len-1个字节 unsigned char window[target_len - 1] = {0}; unsigned char current_byte; int bytes_read = 0; // 先读取前3个字节填充窗口 while (bytes_read < target_len - 1 && is.read(reinterpret_cast<char*>(¤t_byte), 1)) { window[bytes_read] = current_byte; bytes_read++; } // 开始滑动匹配 while (is.read(reinterpret_cast<char*>(¤t_byte), 1)) { // 检查当前窗口+当前字节是否匹配目标 bool match = true; for (int i = 0; i < target_len - 1; i++) { if (window[i] != target[i]) { match = false; break; } } if (match && current_byte == target[target_len - 1]) { std::cout << "Found Matroska Segment EBML ID at position: " << is.tellg() - target_len << std::endl; // 可以选择继续查找或退出 // break; } // 滑动窗口:把窗口内的字节往前移一位,放入当前字节 for (int i = 0; i < target_len - 2; i++) { window[i] = window[i + 1]; } window[target_len - 2] = current_byte; } is.close(); return 0; }
代码说明
- 明确目标字节序列为
0x18, 0x53, 0x80, 0x67,直接用十六进制定义更清晰。 - 用滑动窗口保存最近的3个字节,每次读取新字节后,组合成4字节序列和目标对比,避免重复读取和越界。
- 处理文件打开失败的情况,增加鲁棒性。
- 匹配成功时输出位置(
tellg()返回当前读取位置,减去目标长度就是序列起始位置)。
内容的提问来源于stack exchange,提问作者Silviu Petrut
相关产品推荐
相关产品推荐

