How do I compare two parsed files and add the difference to the first one?

Suppose I have two .dat files; one on my computer and the other on the other side of the earth - the data is constantly serializing into it through QDataStream

.

The data is parsed in the same way - first some identifier and then the object associated with that particular identifier.

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();

      

After a while, the first one might look something like this (illustrative, not syntactically correct):

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

ID:873482025
 dataObject

ID:129845379
 dataObject

ID:836482455
 dataObject

ID:224964811
 dataObject

ID:625444876
 dataObject

ID:215548669
 dataObject

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

      

But the second has not yet caught up.

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

ID:873482025
 dataObject

ID:129845379
 dataObject

ID:836482455
 dataObject

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

      

Is it possible to take both files - determine the differences between them, and then "merge" into those that are absent in the second, but are present in the first?

Obviously this can be achieved by writing a function that extracts the insides of files, classifies the contents separately, compares them, etc. - but is there a way to do this by simply processing the files themselves, without having to parse the content individually?

+3


source to share


1 answer


  • Read both files to extract the sets of identifiers.

  • Read one of the files by adding objects with missing IDs to another file.

You can use QSet

to do arithmetic. In addition, each object needs not only stream operators, but also a static method skipObject

. I also ignore how you differentiate between object types.



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);
}

      

+2


source







All Articles