记录文件的升级和向后兼容性问题

3

我有这样一个文件:

file of record
  Str: string[250];
  RecType: Cardinal;
end;

但是在使用此文件一段时间后,我的客户发现,Str永远不会超过100个字符,并且他需要额外的字段。

在新版本中,我们有这样的文件:

file of packed record
  Str: string[200];
  Reserved: array[1..47] of Byte;
  NewFiled: Cardinal;
  RecType: Cardinal;
end;

这条记录和之前的记录大小相同,在 Str 和 RecType 之间有一个未使用的字节,当对齐到8个字节时。

问题:当旧代码读取此新文件时会发生什么?需要向后兼容。

旧代码读取示例:

var
  FS: TFileStream;
  Rec: record
         Str: string[250];
         RecType: Cardinal;
       end;
...
// reading record by record from file:
FS.Read(Rec, SizeOf(Rec));

你能贴出一些读取它的代码吗? - placeybordeaux
1
在我看来,编写一个快速测试应用程序似乎非常容易,该应用程序可以使用新格式编写一些记录,然后尝试使用旧格式读取它们;它几乎可以立即回答这个问题,并且还可以为您提供未来更改的测试。 - Ken White
我有一个测试,它可以工作,但是我很困惑——字符串字段可能会乱码吗? - Alex Egorov
你使用的是哪个版本的Delphi? - jachguate
1
抱歉,但问题确实与记录的大小有关,如果您发布完全不同大小的记录,那么答案就变成“显然,这行不通,因为您正在读取和写入完全不同大小的记录。”。不过,感谢您的快速编辑。 :-) - Ken White
显示剩余7条评论
1个回答

3

旧版Pascal字符串使用字符串的第一个字节(索引0)来存储字符串的长度。

让我们看一下这个记录的内存:

byte    0  1  2  3  4  5  6  7  8  9 10 11  12  13 ........ 243..246 247..250
value  10 65 66 67 68 69 70 71 72 73 74  0 200 130          NewField RecType

从第11个字节到242个字节,内存中可能包含垃圾数据,程序会忽略这些数据(从未显示过),因为在字节0处,它将值10作为字符串长度,所以字符串变成了'ABCDEFGHIJ'。
这确保了旧程序读取使用最新版本创建的文件时,不会看到字符串末尾的垃圾数据,因为该字符串的视图将仅限于实际字符串大小,并且那些内存位置只是被忽略的。
你需要仔细检查旧程序是否会更改存储的值,以防它将记录写回文件。我认为这也是安全的,但我只是不确定,并且没有Delphi来测试。

我认为字符串格式和旧程序一样,客户将能够查看数据而无需编辑。 - Alex Egorov
1
解释得很好,但问题是关于旧代码读取新记录。由于旧记录将字符串定义为大50字节,因此它确实可能包含某些被忽略的比新记录中的200个字符更长的字符串(例如,如果实际存储了一个250字节的字符串或者由于某种原因用空格填充了一个字符串)。 - Ken White
直到有人第一次使用旧代码实际上在字符串中写入> 200个字节到记录中,并覆盖新代码放置的内容(破坏新代码值),或者新代码在之后进来并覆盖,破坏旧代码的值(因为它仍然具有索引0处大于200的长度字节)。 - Ken White
1
@Ken,是的,但问题是关于读取值是否安全,而不是写入它们。 - jachguate
感谢大家的帮助和评论。 - Alex Egorov
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接