我在Delphi 7.0下开发的软件已在Delphi 2010 RAD Studio XE下升级和开发。它还将用户的设置保存或写入二进制文件。我遇到的问题是我的Delphi 2010应用程序或软件应该读取由Delphi 7.0应用程序创建的二进制文件,但Delphi 2010应用程序在读取二进制文件时遇到问题。这两个软件都是彼此的副本。
我确实将项目的Record Field Alignment选项设置为Delphi 7.0上的1和Delphi 2010上的字节。
当软件读取二进制文件时,我总是遇到异常“读取超出行尾”。
我通过执行以下操作来读取和写入二进制文件。
写入二进制文件:
procedure WriteUnitFile;
var
unitFile: File;
x:integer;
FileHeader:TFileHeader;
begin
if not DemoMode then
begin
FileHeader.id := 'UnitFile';
FileHeader.version := 7;
if fileexists(basedir+unitfilename) then
BackupFile(basedir+unitfilename);
AssignFile(unitFile,baseDir+unitfilename);
if UnitList.Count > 0 then
begin
Rewrite(unitFile,1);
BlockWrite(unitFile, FileHeader, SizeOf(FileHeader));
for x := 0 to UnitList.Count - 1 do
begin
TUnit(UnitList[x]).Write(unitFile);
end;
end
else
DeleteFile(baseDir+unitfilename);
CloseFile(unitFile);
end;
end;
从二进制文件中读取:
procedure ReadUnitFile;
var
unitFile:File;
newUnit,simUnit:TUnit;
ut,TypeCard:TUnitType;
New_Ver_File:TFileHeader;
Address:SmallInt;
State:TUnitState;
SubAddress:SmallInt;
MyfDefs:array[1..20] of SmallInt;
fDefs:array[1..16] of SmallInt;
begin
if FileExists(baseDir + unitfilename) then
begin
oneUnit := false;
AssignFile(unitFile,baseDir+unitfilename);
AssignFile(newUnitFile,baseDir+Dummyfilename);
Reset(unitFile,1);
BlockRead(unitFile,New_Ver_File,SizeOf(New_Ver_File));
Reset(UnitFile,1);
BlockRead(UnitFile,New_Ver_File,SizeOf(New_Ver_File));
while not Eof(UnitFile) do
begin
BlockRead(UnitFile,ut,SizeOf(ut));
case ut of
tutSimulator:newUnit := TSimulator.Create;
tutDX2202:newUnit := TDX2202.Create;
tutDX8884CS:newUnit:=TDX8884CS.Create;
tutDX8F44F: newUnit := TDX8F44F.Create;
tutDX0008:newUnit := TDX0008.Create;
tutDX0800:newUnit := TDX0800.Create;
tutDX8000:newUnit := TDX8000.Create;
tutDX1000:newUnit := TDX1000.Create;
tutDX0100:newUnit := TDX0100.Create;
tutDX4404:newUnit := TDX4404.Create;
tutDX0020:newUnit := TDX0020.Create;
tutDX0080:newUnit := TDX0080.Create;
tutDX8814:newUnit := TDX8814.Create;
tutDX8814CS:newUnit := TDX8814CS.Create;
tutDX8884:newUnit := TDX8884.Create;
else
newUnit := TUnit.Create;
end;
newUnit.Read(unitFile);
if DemoMode then
begin
if oneUnit = true then
begin
simUnit := TSimulator.Create;
simUnit.Assign(newUnit);
newUnit.Free;
newUnit := simUnit;
end
else
begin
oneUnit := true;
end;
end;
unitList.Add(newUnit);
end;
CloseFile(unitfile);
UnitsDlg.UnitGrid.RowCount := unitList.Count+1;
if UnitsDlg.UnitGrid.RowCount > 1 then
UnitsDlg.UnitGrid.FixedRows := 1;
UnitsDlg.FillIn;
end
else
begin
UnitsDlg.UnitGrid.RowCount := 1;
end;
end;
更新 以下是用户定义的数据类型:
TFileHeader = record
id:string[32];
version:SmallInt;
end;
TUnitType = (tutUnused,tutSimulator,tutDX2202,tutDX0008,tutDX0800,tutDX8000,
tutDX1000,tutDX4404,tutDX0020,tutDX8814,tutDX8814CS,
tutDX8884,tutDX8884CS,tutDX8f44f,tutDX0080,tutDX0100,tutLast);
TUnitState = (tusDisabled,tusEnabled);
TUnit = class(TObject)
changeLink:TUnit;
Address: SmallInt;
SubAddress:SmallInt;
State:TUnitState;
uType:TUnitType;
RegCnt:integer;
fRegs:array[1..20] of SmallInt;
fDefs:array[1..20] of SmallInt;
MsgCnt:LongWord;
RxCnt:LongWord;
BreakCnt: LongWord;
LineErrCnt: LongWord;
OtherErrCnt:LongWord;
TimeoutCnt: LongWord;
BadMsgErrCnt:LongWord;
XSumErrCnt:LongWord;
OutsFlag:Boolean;
CommBits:LongWord;
OfflineCnt:integer;
Online:Boolean;
CurReg:integer;
selectedonce,usedIP:Boolean;
LastDigitalOut,LastDigitalIn,
CurRegOut,umsglen,urmsglen,
dummycount,Unitlocation,
CommLocation:integer;
private
public
followed by list of procedures and functions...
end;
我有什么遗漏或不太了解吗?
我忘记提到的一件事是,Delphi 2010应用程序读取和写入二进制文件就好了而不对代码进行任何更改,但只有在读取Delphi 7.0创建的文件时才会出现问题。应用
显然,这个问题与记录字段对齐有关。那么,如果将Delphi 7.0设置为1,我应该在Delphi 2010(字节,Word,双字,四字)上设置它。
提前致谢。
答案 0 :(得分:4)
密钥位于TFileHeader
声明中(可能是TUnit
和TUnitType
声明)。您应该将这些定义添加到您的问题中。
如果您在其中任何一个记录中定义纯字符串,则需要在Delphi 2010中使用ShortString
而不是String
来使其正常工作。
Delphi 7中的字符串=每个字符1个字节 Delphi 2010中的字符串=每个字符2个字节。
您的上次更新并未真正显示任何新信息,但fDefs
过程中的ReadUnitFile
变量定义为array[1..16] of SmallInt;
,但在TUnit
类中,fDefs
是array[1..20] of SmallInt;
?
似乎没有使用fDefs
变量,但这可能是导致EOL错误的差异?
无论如何,您应该将这样的数组定义为通用Type
,以确保它们可以作为兼容类型传递并相互分配(例如,作为方法中的参数)。
错误不在字符串中,而是在TObject
的大小中。
在Delphi 2009中,TObject
将大小从4个字节增加到8个字节
前4个字节是指向对象VMT的指针(因为它已经存在了很长时间),在最后4个字节(IIRC)中,可以包含对同步监视器的引用。
看看这篇好文章:http://blogs.teamb.com/craigstuntz/2009/03/25/38138/
答案 1 :(得分:0)
在Delphi 7和2010中用packed
关键字标记您写入文件的所有记录。
答案 2 :(得分:0)
我不知道答案,但我可以就如何正确识别问题给你一些指示。一旦发现问题,解决方案通常会立即跟进。
由于您收到"read beyond end of
行 file"
错误,您显然正在处理更改记录大小。许多事情都可能导致:
packed record
,否则编译器会假定它仅在内部使用,因此可以自由更改它的对齐方式。由于CPU(和OS')在D7 - D2010时间范围内改变了分配,因此可以预期两个编译器之间的对齐方式会发生变化。Char
数据,则可能导致记录大小发生变化。回到调试。您可以编写一些简单的代码来显示记录本身的大小,每个字段的大小以及每个字段的偏移量。从D7和D2010运行此代码,记下所有数字并解决可能的差异:
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils;
type
TTestRecord = record
IntField: Integer;
ShortStrField1: string[6];
ShortStrField2: string[5];
D: Double;
end;
var R: TTestRecord;
begin
WriteLn('TTestRecord size: ', SizeOf(R));
WriteLn('IntField size: ', SizeOf(R.IntField), ', offset: ', Integer(@R.IntField) - Integer(@R));
WriteLn('ShortStrField1 size: ', SizeOf(R.ShortStrField1), ', offset: ', Integer(@R.ShortStrField1) - Integer(@R));
WriteLn('ShortStrField2 size: ', SizeOf(R.ShortStrField2), ', offset: ', Integer(@R.ShortStrField2) - Integer(@R));
WriteLn('D size: ', SizeOf(R.D), ', offset: ', Integer(@R.D) - Integer(@R));
ReadLn;
end.
获得此信息后,您可以更改记录,使其在Delphi 7和Delphi 2010上看起来都一样。我将从Delphi 7平台开始;我首先将定义更改为packed record
,然后在记录中添加额外的填充字节以保持字段偏移。新类型定义如下所示:
TTestRecord = packed record
IntField: Integer;
ShortStrField1: string[6];
ShortStrField2: string[5];
_DummyPadding: array[0..6] of Byte; // Added to fix D's alignment after adding "packed"
D: Double;
end;
完成此操作后,转到Delphi 2010,保留packed
修饰符和所有手动添加的填充。运行显示字段大小和对齐的代码,特别注意各个字段的大小:如果您的记录中有任何Char
字段,则需要将其更改为AnsiChar
。幸运的是,Delphi 7和Delphi 2010都知道AnsiChar
并认为它长1个字节。