std::fstream 封装加校验
选自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;
// 获取数据的size
if (!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);

浙公网安备 33010602011771号