将两个rosbag文件合并到一个新的robag文件里是很容易的,open两个源文件时指定bagmode::BagMode::Read(或BagMode::Read),然后read,open保存合并结果的新文件时指定bagmode::BagMode::Write(BagMode::Write),不用多说,如果将两个bag合并将结果保存在其中一个bag里,或者读取一个bag中的数据输入模型进行推理,然后把识别结果写回到此bag中,这些操作处理的本质涉及到对同一bag文件的同时读写处理,该怎么做呢?
查了一下网上资料,都是说怎么单独读和写bag文件的没有用,查看ros.org上文档也没有用的信息,只好去翻看rosbag的源码(C++源码需要到https://github.com/ros/ros_comm这里下载,ros安装时安装的都是C++代码编译成出来的so库以及对应的python代码,所以ros安装目录下只能看python版的代码),发现还有个BagMode就是BagMode::Append,看了一下相关代码,用Append这种模式就能解决同时读写同一个bag文件的问题:
void Bag::open(string const& filename, uint32_t mode) {
mode_ = (BagMode) mode;
if (mode_ & bagmode::Append)
openAppend(filename);
else if (mode_ & bagmode::Write)
openWrite(filename);
else if (mode_ & bagmode::Read)
openRead(filename);
else
throw BagException((format("Unknown mode: %1%") % (int) mode).str());
// Determine file size
uint64_t offset = file_.getOffset();
seek(0, std::ios::end);
file_size_ = file_.getOffset();
seek(offset);
}
void Bag::openRead(string const& filename) {
file_.openRead(filename);
readVersion();
switch (version_) {
case 102: startReadingVersion102(); break;
case 200: startReadingVersion200(); break;
default:
throw BagException((format("Unsupported bag file version: %1%.%2%") % getMajorVersion() % getMinorVersion()).str());
}
}
void Bag::openWrite(string const& filename) {
file_.openWrite(filename);
startWriting();
}
void Bag::openAppend(string const& filename) {
file_.openReadWrite(filename);
readVersion();
if (version_ != 200)
throw BagException((format("Bag file version %1%.%2% is unsupported for appending") % getMajorVersion() % getMinorVersion()).str());
startReadingVersion200();
// Truncate the file to chop off the index
file_.truncate(index_data_pos_);
index_data_pos_ = 0;
// Rewrite the file header, clearing the index position (so we know if the index is invalid)
seek(file_header_pos_);
writeFileHeaderRecord();
// Seek to the end of the file
seek(0, std::ios::end);
}
我们可以看到当mode是BagMode::Append时,open()调用的openAppend()函数里第一句就是
file_.openReadWrite(filename);
这个openReadWrite()其实就是以r+b方式打开文件,实现代码在chunked_file.cpp里:
ChunkedFile::ChunkedFile() :
file_(NULL),
offset_(0),
compressed_in_(0),
unused_(NULL),
nUnused_(0)
{
stream_factory_ = boost::make_shared<StreamFactory>(this);
}
ChunkedFile::~ChunkedFile() {
close();
}
void ChunkedFile::openReadWrite(string const& filename) { open(filename, "r+b"); }
void ChunkedFile::openWrite (string const& filename) { open(filename, "w+b"); }
void ChunkedFile::openRead (string const& filename) { open(filename, "rb"); }
void ChunkedFile::open(string const& filename, string const& mode) {
// Check if file is already open
if (file_)
throw BagIOException((format("File already open: %1%") % filename_.c_str()).str());
// Open the file
if (mode == "r+b") {
// check if file already exists
#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
fopen_s( &file_, filename.c_str(), "r" );
#else
file_ = fopen(filename.c_str(), "r");
#endif
if (file_ == NULL)
// create an empty file and open it for update
#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
fopen_s( &file_, filename.c_str(), "w+b" );
#else
file_ = fopen(filename.c_str(), "w+b");
#endif
else {
if (fclose(file_) != 0)
throw BagIOException((format("Error closing file: %1%") % filename.c_str()).str());
// open existing file for update
#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
fopen_s( &file_, filename.c_str(), "r+b" );
#else
file_ = fopen(filename.c_str(), "r+b");
#endif
}
}
else