Torrent文件是遵循BitTorrent协议的二进制元数据文件,采用Bencode编码(非JSON/纯文本),结构含嵌套字典、列表、整数和字节串;直接用ifstream读取仅得原始字节,必须经Bencode解析才能提取announce、info、文件列表等关键字段。

什么是Torrent文件,为什么不能直接用ifstream读
Torrent 文件是遵循 BitTorrent 协议的 .torrent 文件,本质是 Bencode 编码 的二进制数据(不是 JSON,也不是纯文本),结构为嵌套的字典、列表、整数和字节串。直接用 std::ifstream 读成字符串或 raw bytes 后,不解析就无法提取 info 字段、announce、文件列表等关键信息。
用 libtorrent(C++)最稳妥,但要注意链接和初始化
libtorrent 是目前 C++ 生态中唯一成熟、持续维护、支持完整 Bittorrent 协议解析的库。它能直接加载 .torrent 并暴露结构化字段,比手写 Bencode 解析器靠谱得多。
实操要点:
- 必须链接
-ltorrent(Linux/macOS)或正确配置 Windows 的libtorrent.lib;漏掉会导致undefined reference to 'libtorrent::bdecode'类错误 - 推荐用
libtorrent::torrent_info构造函数加载本地文件:torrent_info ti("xxx.torrent"),它内部已处理 Bencode 解析、校验和 UTF-8 转换 - 若需只读元数据(不走网络),确保传入空
libtorrent::settings_pack或跳过 session 初始化——否则可能触发 DNS 查询或 tracker 连接尝试 - 常见坑:
ti.name()返回的是 info 字典里的name(通常是根目录名),不是文件系统路径;真实文件列表要遍历ti.files().file_path(i)
示例片段:
立即学习“C++免费学习笔记(深入)”;
libtorrent::torrent_info ti("sample.torrent");
std::cout << "Announce: " << ti.trackers()[0].url << "\n";
std::cout << "Name: " << ti.name() << "\n";
for (int i = 0; i < ti.num_files(); ++i) {
std::cout << "File: " << ti.files().file_path(i).string() << "\n";
}
手写简易 Bencode 解析器?仅限调试,别用于生产
如果你只是想快速 inspect 一个 torrent 文件结构(比如验证是否损坏),可以写个极简 parser 提取顶层 key。但注意:Bencode 支持递归嵌套、任意长度字节串、无类型标识,完整实现极易出错。
关键边界条件:
-
i-123e是合法整数,负号后紧跟数字,e结尾——漏判负数会崩溃 - 字节串格式是
<length>:<data>,例如6:foobar;长度可能是 10 位数,不能用atoi简单截断 -
d/e成对出现,深度嵌套时栈溢出风险高(.torrent 文件里info字典常嵌套多层) - UTF-8 不保证,
name和path字段实际是 byte string,C++ std::string 存储没问题,但转std::u8string或显示前需确认编码
Python 的 bencodepy 可作交叉验证,但 C++ 项目里别混用
开发阶段,你可以用 Python 快速 dump torrent 内容:python -c "import bencodepy; print(bencodepy.decode_file('x.torrent'))"。这能帮你确认 C++ 解析结果是否合理——比如 info 字典里 piece length 是否为 2 的幂、pieces 字段长度是否为 20 的倍数。
但不要在 C++ 项目里通过 system("python ...") 调用它:跨进程开销大、依赖外部环境、无法捕获结构化数据、Windows 上路径空格和引号容易崩。
真正要集成,要么用 libtorrent,要么接受手写 parser 的维护成本——没有中间态。


















