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);
posted @ 2025-01-06 16:59  narjaja  阅读(20)  评论(0)    收藏  举报