选自Cartographer_ROS
proto_stream_interface.h
// A writer for writing proto messages to a pbstream.
class ProtoStreamWriterInterface {public:virtual ~ProtoStreamWriterInterface() {}// Serializes, compressed and writes the 'proto' to the file.virtual void WriteProto(const google::protobuf::Message& proto) = 0;// This should be called to check whether writing was successful.virtual bool Close() = 0;
};// A reader of the format produced by ProtoStreamWriter.
class ProtoStreamReaderInterface {public:ProtoStreamReaderInterface() = default;virtual ~ProtoStreamReaderInterface() {}// Deserialize compressed proto from the pb stream.virtual bool ReadProto(google::protobuf::Message* proto) = 0;// 'End-of-file' marker for the pb stream.virtual bool eof() const = 0;
};
proto_stream.h
class ProtoStreamWriter : public ProtoStreamWriterInterface {public:ProtoStreamWriter(const std::string& filename);~ProtoStreamWriter() = default;ProtoStreamWriter(const ProtoStreamWriter&) = delete;ProtoStreamWriter& operator=(const ProtoStreamWriter&) = delete;void WriteProto(const google::protobuf::Message& proto) override;bool Close() override;private:void Write(const std::string& uncompressed_data);std::ofstream out_;
};// A reader of the format produced by ProtoStreamWriter.
class ProtoStreamReader : public ProtoStreamReaderInterface {public:explicit ProtoStreamReader(const std::string& filename);~ProtoStreamReader() = default;ProtoStreamReader(const ProtoStreamReader&) = delete;ProtoStreamReader& operator=(const ProtoStreamReader&) = delete;bool ReadProto(google::protobuf::Message* proto) override;bool eof() const override;private:bool Read(std::string* decompressed_data);std::ifstream in_;
};
proto_stream.h
// First eight bytes to identify our proto stream format.
const uint64 kMagic = 0x7b1d1f7b5bf501db;// 写入8个字节的校验位
void WriteSizeAsLittleEndian(uint64 size, std::ostream* out) {for (int i = 0; i != 8; ++i) {out->put(size & 0xff);size >>= 8;}
}// 读取前8个字节的值, 进行累加
bool ReadSizeAsLittleEndian(std::istream* in, uint64* size) {*size = 0;for (int i = 0; i != 8; ++i) {*size >>= 8;*size += static_cast<uint64>(in->get()) << 56;}return !in->fail();
}} // namespace// 以二进制方式, 写入的方式打开文件, 并写入8个字节的数据校验
ProtoStreamWriter::ProtoStreamWriter(const std::string& filename): out_(filename, std::ios::out | std::ios::binary) {WriteSizeAsLittleEndian(kMagic, &out_);
}// 将传入的数据先进行压缩, 再写入到文件中
void ProtoStreamWriter::Write(const std::string& uncompressed_data) {std::string compressed_data;// 对数据进行压缩common::FastGzipString(uncompressed_data, &compressed_data);// 根据数据的size写入文件WriteSizeAsLittleEndian(compressed_data.size(), &out_);// 将内存中 compressed_data 以二进制的形式写入文件out_.write(compressed_data.data(), compressed_data.size());
}// 将数据写入文件中
void ProtoStreamWriter::WriteProto(const google::protobuf::Message& proto) {std::string uncompressed_data;proto.SerializeToString(&uncompressed_data);// 压缩并写入Write(uncompressed_data);
}// 关闭打开的文件
bool ProtoStreamWriter::Close() {out_.close();return !out_.fail();
}// 读取pbstream文件, 并对前8个字节的数据进行校验
ProtoStreamReader::ProtoStreamReader(const std::string& filename): in_(filename, std::ios::in | std::ios::binary) {uint64 magic;// 对前8个字节的数据进行校验if (!ReadSizeAsLittleEndian(&in_, &magic) || magic != kMagic) {in_.setstate(std::ios::failbit);}CHECK(in_.good()) << "Failed to open proto stream '" << filename << "'.";
}// 读取数据并解压
bool ProtoStreamReader::Read(std::string* decompressed_data) {uint64 compressed_size;// 获取数据的sizeif (!ReadSizeAsLittleEndian(&in_, &compressed_size)) {return false;}// 根据size生成字符串std::string compressed_data(compressed_size, '\0');// 读取数据放入compressed_data中if (!in_.read(&compressed_data.front(), compressed_size)) {return false;}// 进行解压common::FastGunzipString(compressed_data, decompressed_data);return true;
}// 读取数据并返回protobuf格式的数据
bool ProtoStreamReader::ReadProto(google::protobuf::Message* proto) {std::string decompressed_data;return Read(&decompressed_data) && proto->ParseFromString(decompressed_data);
}bool ProtoStreamReader::eof() const { return in_.eof(); }
调用main
string state_filename;
ProtoStreamReader stream(state_filename);