Delphi-错误的数据写入,然后使用BlockWrite/BlockRead读取



Delphi Tokyo-I并创建一个配置文件。我使用BlockWrite编写配置文件,然后使用BlockRead读取。我读字符串时出错了。我得到的似乎是亚洲字符。。。

我认为问题出在我定义ReadString例程的方式上。

这是我的WriteString例程

procedure WriteString(s: ShortString);
begin { WriteString }
BlockWrite(fil, s, succ(length(s)));
end; { WriteString }

我的ReadString例程应该返回相同的数据,但事实并非如此。这是ReadString代码。

function ReadString: string;
var
count: Cardinal;
l: integer;
begin
BlockRead(fil, l, sizeof(integer), count);
SetLength(Result, l);
BlockRead(fil, Result[1], l, count);
end;

从配置文件中读取的第一个值是布尔值,并且它似乎是正确读取文件的。下一个值是一个字符串,并且是混乱的。感谢您的帮助。

这是FULL WriteConfig和ReadConfig例程,以及SetConfigValues,它只创建一些测试数据。

procedure SetConfigValues;
begin
//
gCMD_Globals.Load_Table := True;
gCMD_Globals.DB_Tablename := 'my Test Table';
gCMD_Globals.Create_Backup := True;
gCMD_Globals.Delete_Existing_Backup := False;
gCMD_Globals.Truncate_Existing_Table := True;
SetLength(gCMD_Detail, 2);
gCMD_Detail[0].CommandType := 'CMD1';
gCMD_Detail[0].P1 := 'P11';
gCMD_Detail[0].P2 := 'P21';
gCMD_Detail[0].P3 := 'P31';
gCMD_Detail[1].CommandType := 'CMD1';
gCMD_Detail[1].P1 := 'P12';
gCMD_Detail[1].P2 := 'P22';
gCMD_Detail[1].P3 := 'P32';
end;

procedure WriteConfigFile(FileName: string);
var
fil: file;
i: integer;
num: word; { allows up to 65535 records }
const
ver: byte = LatestFileVersion;
procedure WriteString(s: ShortString);
begin { WriteString }
BlockWrite(fil, s, succ(length(s)));
end; { WriteString }
begin { WriteConfigFile }
assignFile(fil, FileName);
rewrite(fil, 1); { Create the file }
BlockWrite(fil, ver, sizeof(ver)); { Write the file version }
// Now we need to write the gCMD_Globals record
with gCMD_Globals do
begin { write the data }
BlockWrite(fil, Load_Table, sizeof(Load_Table));
WriteString(DB_Tablename);
BlockWrite(fil, Create_Backup, sizeof(Create_Backup));
BlockWrite(fil, Delete_Existing_Backup, sizeof(Delete_Existing_Backup));
BlockWrite(fil, Truncate_Existing_Table, sizeof(Truncate_Existing_Table));
end;
num := length(gCMD_Detail);
BlockWrite(fil, num, sizeof(num)); { Write the number of records }
for i := 0 to high(gCMD_Detail) do
with gCMD_Detail[i] do
begin { write the data }
WriteString(CommandType);
WriteString(P1);
WriteString(P2);
WriteString(P3);
end; { with }
CloseFile(fil);
end; { WriteConfigFile }
procedure ReadConfigFile(FileName: string);
var
fil: file;
i: integer;
num: word; { allows up to 65535 records }
ver: byte;
function ReadString: string;
var
count: Cardinal;
l: integer;
begin
BlockRead(fil, l, sizeof(integer), count);
SetLength(Result, l);
BlockRead(fil, Result[1], l, count);
end;

begin { ReadFile }
assignFile(fil, FileName);
reset(fil, 1); { Open the file }
BlockRead(fil, ver, sizeof(ver)); { Read the file version }
// Now we need to write the gCMD_Globals record
with gCMD_Globals do
begin { write the data }
BlockRead(fil, Load_Table, sizeof(Load_Table));
DB_Tablename := ReadString;
BlockRead(fil, Create_Backup, sizeof(Create_Backup));
BlockRead(fil, Delete_Existing_Backup, sizeof(Delete_Existing_Backup));
BlockRead(fil, Truncate_Existing_Table, sizeof(Truncate_Existing_Table));
end;
BlockRead(fil, num, sizeof(num)); { Read the number of records }
SetLength(gCMD_Detail, num);
for i := 0 to high(gCMD_Detail) do
with gCMD_Detail[i] do
begin { Read the data }
CommandType := ReadString;
P1 := ReadString;
P2 := ReadString;
P3 := ReadString;
end; { with }
CloseFile(fil);
end; { ReadConfigFile }

ShortString是一种使用1字节长度的8位字符串类型。您将ShortString正确写入文件(假设文件的"记录"大小已预先设置为1(,但没有正确读取。对于字符串长度,您读取的是4字节的integer而不是1字节的AnsiChar/Byte,然后将8位字符读取到16位的UnicodeString而不是ShortString

使用这个替代:

function ReadString: string;
var
len: Byte;
s: ShortString;
begin
BlockRead(fil, len, 1);
SetLength(s, len);
BlockRead(fil, s[1], len);
Result := string(s);
end;

不过,我根本不建议使用ShortString。您使用的是Delphi的Unicode版本,因此如果您可以自由更改文件布局,我建议让WriteString()(Unicode)String为输入并将其转换为UTF-8进行存储,然后让ReadString()进行相反的操作,例如:

procedure WriteString(const s: UnicodeString);
var
utf: UTF8String;
len: integer;
begin
utf := UTF8String(s);
len := Length(utf);
BlockWrite(fil, len, sizeof(len));
BlockWrite(fil, PAnsiChar(utf)^, len);
end;
function ReadString: UnicodeString;
var
len: integer;
utf: UTF8String;
begin
BlockRead(fil, len, sizeof(len));
SetLength(utf, len);
BlockRead(fil, PAnsiChar(utf)^, len);
Result := UnicodeString(utf);
end;

对于短字符串,长度为ord(s[0](,并且只写入一个字节。但是你在l中读取了四个字节,所以你不能指望它会起作用。作为修复,您可以将长度块写为整数,也可以块读字节变量l。

最新更新