0%

protobuf 压缩

在 github 上我们能找到 protobuf 的 最新发布版本

在发布的压缩包中,我们只需要关注 protobuf-cpp-version.zip/tar.gz。有时 protobuf-version-win32.zip 也会让人疑惑,我们到底需不需要这个文件呢?让我们看一下其中的 readme.txt

This package contains a precompiled binary version of the protocol buffer compiler (protoc). This binary is intended for users who want to use Protocol Buffers in languages other than C++ but do NOT want to compile protoc themselves.

简单说,是给 C++ 开发者之外的码农用的。

但是,If you intend to use the included well known types,我们还是需要下载后者的。毕竟前者中 .proto 原型混杂在了大量的头文件中,而这里的原型文件一目了然。

二进制

在解析文件服务器上的历史 k 线时,碰到了比较特殊的问题:

通过 asio 网络通信 streambuf 解析正常

1
2
3
4
5
6
7
8
9
10
11
void client_k::parsebody(asio::streambuf& buf, yuanda::GluedK& calstick)
{
if (buf.size())
{
//解析k线文件
yuanda::GluedCandleStickCombo combo;
std::istream response_stre(&buf);
if (auto success = combo.ParseFromIstream(&response_stre))
// ... true/success
}
}

但是将文件下载下来,通过 fstream 解析时,个别文件正常,大多数文件在 ParaseFromIstream() 总是解释失败

1
2
3
4
5
6
7
8
9
std::fstream ff;
ff.open(u8R"(F:\_DayK\SH600000\glued_candlestick_SH600000_5_0_2000.data)");
if (ff.is_open())
{
yuanda::GluedCandleStickCombo combo;
std::istream is(ff.rdbuf());
if (auto success = combo.ParseFromIstream(&is))
// ... false/fail
}

进一步调试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
std::fstream ff;
ff.open(u8R"(F:\_DayK\SH600000\candlestick_SH600000_5_0_2000.data)");
if (ff.is_open())
{
yuanda::CandleStick calstick;
int headsize = 0, bodysize = 0;
ff.read((char*)&headsize, sizeof(int));
ff.read((char*)&bodysize, sizeof(int));
auto kheader = std::shared_ptr<char>(new char[headsize], [](char* ptr) { delete[] ptr; });
auto kbody = std::shared_ptr<char>(new char[bodysize], [](char* ptr) { delete[] ptr; });
ff.read(kheader.get(), headsize);
assert(ff.gcount() == headsize);
ff.read(kbody.get(), bodysize);
auto s2 = ff.gcount();
assert(s2 == bodysize); // false 断言在此处失败

查看 std::basic_istream::read() 的说明

释出并存储字符,直至出现任何下列条件:

释出并存储了 count 个字符
输入序列上的文件尾条件(该情况下调用 setstate(failbit|eofbit) )。成功释出的字符数能用 gcount() 查询。

问题根源

文件尾 EOF 到底是什么呢?替代字符 \0x1A

二进制与文本模式

默认以文本流打开文件,但文本流如果要保证与先前写入“一致”(与先前写到该文本流者比较相等)是有好多限制的,其中一条就是

数据只由打印字符和控制字符 \t 及 \n 组成(尤其是 Windows OS 上,字符 ‘\0x1A’ 终止输入)

二进制流,从二进制流读取的数据始终与先前写出到该流者比较相等。

POSIX implementations do not distinguish between text and binary streams (there is no special mapping for \n or any other characters)