Delphi-错误的数据写入,然后使用BlockWrite/BlockRead读取
DelphiTokyo-I并创建一个配置文件。我使用BlockWrite写入配置文件,然后使用BlockRead读取它。当我读字符串时,有点不对劲。我得到的似乎是亚洲字符 我认为问题在于我定义ReadString例程的方式 这是我的写作常规Delphi-错误的数据写入,然后使用BlockWrite/BlockRead读取,delphi,Delphi,DelphiTokyo-I并创建一个配置文件。我使用BlockWrite写入配置文件,然后使用BlockRead读取它。当我读字符串时,有点不对劲。我得到的似乎是亚洲字符 我认为问题在于我定义ReadString例程的方式 这是我的写作常规 procedure WriteString(s: ShortString); begin { WriteString } BlockWrite(fil, s, succ(length(s))); end; { 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;
从配置文件中读取的第一个值是一个布尔值,似乎正确读取了该文件。下一个值是一个字符串,它被弄乱了。谢谢你的帮助
下面是完整的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 }
对于短字符串,长度为ord(s[0]),只写入一个字节。但是你把四个字节读入l。所以你不能指望这会奏效。作为修复,您可以将长度分块写入整数或分块读取字节变量l。a
ShortString
是一种使用1字节长度的8位字符串类型。您正在将短字符串
正确地写入文件(假设文件的“记录”大小事先已设置为1),但您没有正确地读回它。您正在读取一个4字节的整数
,而不是一个1字节的AnsiChar
/字节
作为字符串长度,然后您正在将8位字符读入一个16位的UnicodeString
而不是短字符串
改用这个:
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;
不过,我不建议使用短字符串。您使用的是Unicode版本的Delphi,因此如果您可以随意更改文件布局,我建议您使用WriteString()
将(Unicode)字符串作为输入,并将其转换为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;
现在是2018年。为什么你还是Pascal IO和ANSI?例如,使用JSON会更容易,并且能够支持Unicode,而不必编写手动解析代码。我没有兴趣告诉你如何修复这个代码。我的强烈建议是扔掉它,用更现代的东西。这很有帮助。非常感谢。您的代码中有一个bug。最后一行应该是。。。结果:=单次破坏(utf);您可能希望更改该值以供将来参考。。。