如何比较两个已解析的文件并将差异附加到第一个?
How to compare two parsed files and append the difference to the first?
假设我有两个.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------------------------------------//
是否可以获取两个文件 – 检测它们之间的差异,然后 "fuse" 在第二个文件中缺少但在第一个文件中存在的差异?
显然这可以通过编写一个函数来实现,提取文件的内部结构,对内容进行单独分类,比较它们等等——但是有没有一种方法可以通过只处理文件本身来做到这一点,而不必分别解析内容?
读取两个文件以提取 Id 集。
读取其中一个文件,同时将缺少 ID 的对象附加到另一个文件。
您可以利用 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);
}
假设我有两个.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------------------------------------//
是否可以获取两个文件 – 检测它们之间的差异,然后 "fuse" 在第二个文件中缺少但在第一个文件中存在的差异?
显然这可以通过编写一个函数来实现,提取文件的内部结构,对内容进行单独分类,比较它们等等——但是有没有一种方法可以通过只处理文件本身来做到这一点,而不必分别解析内容?
读取两个文件以提取 Id 集。
读取其中一个文件,同时将缺少 ID 的对象附加到另一个文件。
您可以利用 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);
}