如何比较两个解析的文件并将差异追加到第一个?

时间:2015-08-03 18:28:44

标签: c++ qt serialization qdatastream

假设我有两个.dat文件;一个在我的计算机上,另一个在地球的另一边 - 数据通过QDataStream不断被序列化。

以相同的方式解析数据 - 首先是某种ID,然后是与该特定ID相关联的对象。

QFile file("data.dat");
QDataStream stream(&file);

file.open("QIODevice::ReadWrite");

stream << *id*;          // ID goes in.
stream << *data_object*; // Object with interesting data is serialized into the file.

file.close();

过了一会儿 - 第一个可能看起来像这样(插图式,语法不正确):

//-------------------------------------DATA.DAT------------------------------------//

ID:873482025
 dataObject

ID:129845379
 dataObject

ID:836482455
 dataObject

ID:224964811
 dataObject

ID:625444876
 dataObject

ID:215548669
 dataObject

//-------------------------------------DATA.DAT------------------------------------//

但第二个还没有赶上。

//-------------------------------------DATA.DAT------------------------------------//

ID:873482025
 dataObject

ID:129845379
 dataObject

ID:836482455
 dataObject

//-------------------------------------DATA.DAT------------------------------------//

是否可以同时取两个文件 - 检测它们之间的差异,然后在第二个中缺少的那些“融合”但是在第一个中存在?

显然,这可以通过编写一个函数来提取文件的内部,分别对内容进行分类,比较它们等等来实现 - 但是有没有办法通过自己处理文件来实现这一点,而无需解析内容单独?

1 个答案:

答案 0 :(得分:2)

  1. 读取这两个文件以提取Id集。

  2. 读取其中一个文件,同时将缺少ID的对象附加到另一个文件。

  3. 您可以利用QSet来设置算术。此外,每个对象不仅需要流操作符,还需要skipObject静态方法。我也忽略了你如何区分对象类型。

    typedef qint32_t Id;
    
    bool isOk(const QDataStream & str) { return str.status() == QDataStream::Ok; }
    
    class Object {
      ...
    public:
      static void skipObject(QDataStream & str) {
        qint8 format;
        str >> format;
        if (format == 0)
          str.skipRawData(32); // e.g. format 0 of this object is 32 bytes long
        ...
      }
    };
    
    QPair<QSet<Id>, bool> getIds(const QString & path) {
      QSet<Id> ids;
      QFile file(path);
      if (!file.open(QIODevice::ReadOnly)) return ids;
      QDataStream stream(&file);
      while (!stream.atEnd()) {
        stream >> id;
        Object::skipObject(stream);
        if (ids.contains(id))
          qWarning() << "duplicate id" << id << "in" << path;
        ids.insert(id);
      }
      return qMakePair(ids, isOk(stream));
    }
    
    bool copyIds(const QString & src, const QString & dst, const QSet<Id> & ids) {
      QFile fSrc(src), fDst(dst);
      if (! fSrc.open(QIODevice::ReadOnly)) return false;
      if (! fDst.open(QIODevice::WriteOnly | QIODevice::Append)) return false;
      QDataStream sSrc(&fSrc), sDst(&fDst);
      while (!sSrc.atEnd()) {
        Id id;
        sSrc >> id;
        if (ids.contains(id)) {
           Object object;
           sSrc >> object;
           sDst << id << object;
        } else
           Object::skipObject(sSrc);     
      }
      return isOk(sSrc) && isOk(sDst);
    }
    
    bool copyIds(const QString & src, const QString & dst) {
      auto idsSrc = getIds(src);
      auto idsDst = getIds(dst);
      if (!idsSrc.second || !idsDst.second) return false;
      auto ids = idsSrc.first - idsDst.first; 
      return copyIds(src, dst, ids);
    }