Rob*_*son 0 delphi record delphi-xe8
在 XE8 中处理我的项目时,我需要保存和读取自定义项目文件,这些文件存储不同类型的变量和记录。最初,我解决这个问题的方法似乎有效,但在实际项目中却被证明是错误的。
我创建文件、存储“类别”记录的方法:
var
SavingStream: TFileStream;
i,j: Integer;
begin
SavingStream:=TFileStream.Create('SAVE.test', fmCreate or fmOpenWrite or fmShareDenyWrite);
SavingStream.Position:=0;
i:=Length(Categories); **// storing size of an array in a temp variable**
SavingStream.WriteBuffer(i,SizeOf(i)); **// for some reason i couldn't save it directly**
for i:=0 to Length(Categories)-1 do
begin
**{ String }**
SavingStream.WriteBuffer(Categories[i].Name,SizeOf(Categories[i].Name));
**{ Integer }**
SavingStream.WriteBuffer(Categories[i].ID,SizeOf(Categories[i].ID));
**{ Boolean }**
SavingStream.WriteBuffer(Categories[i].Default,SizeOf(Categories[i].Default))
**{ Same routine for dynamic array }**
j:=Length(Categories[i].ChildrenType);
SavingStream.WriteBuffer(j,SizeOf(j));
if j>=1 then for j:=0 to Length(Categories[i].ChildrenType)-1 do SavingStream.WriteBuffer(Categories[i].ChildrenType[j],SizeOf(Categories[i].ChildrenType[j]));
end;
end;
Run Code Online (Sandbox Code Playgroud)
然后阅读它:
var
SavingStream: TFileStream;
i,j: Integer;
begin
try
SavingStream.ReadBuffer(i,SizeOf(i));
SetLength(Categories,i);
for i:=0 to Length(Categories)-1 do
begin
SavingStream.ReadBuffer(Categories[i].Name,SizeOf(Categories[i].Name));
SavingStream.ReadBuffer(Categories[i].ID,SizeOf(Categories[i].ID));
SavingStream.ReadBuffer(Categories[i].Default,SizeOf(Categories[i].Default));
SavingStream.ReadBuffer(j,SizeOf(j));
SetLength(Categories[i].ChildrenType,j);
if j>=1 then for j:=0 to Length(Categories[i].ChildrenType)-1 do SavingStream.ReadBuffer(Categories[i].ChildrenType[j],SizeOf(Categories[i].ChildrenType[j]));
end;
finally
SavingStream.Free;
end;
Run Code Online (Sandbox Code Playgroud)
主要问题之一是我不完全理解这种方法背后的逻辑。据我了解,SizeOf(i) 基本上是说获取同质文件的某一部分并将其作为变量的值。但是如何存储大小可变的字符串和数组呢?我知道可以限制记录本身的大小,但是我不想限制某些字符串变量。
因此,我需要您的建议,我使用的方法是否有效,以及如何使其在我的具体情况下发挥作用。也许有更好的方法来存储这些信息?请记住,我必须存储各种不同类型,包括图像。
提前谢谢。
您需要将可变长度数据(例如字符串)序列化为不包含任何指向其他内存地址的指针的平面格式。
尝试这样的事情:
procedure WriteIntegerToStream(Stream: TStream; Value: Integer);
begin
Stream.WriteBuffer(Value, Sizeof(Value));
end;
procedure WriteBooleanToStream(Stream: TStream; Value: Boolean);
begin
Stream.WriteBuffer(Value, Sizeof(Value));
end;
procedure WriteStringToStream(Stream: TStream; const Value: String);
var
S: UTF8String;
Len: Integer;
begin
S := UTF8String(Value);
Len := Length(S);
WriteIntegerToStream(Stream, Len);
Stream.WriteBuffer(PAnsiChar(S)^, Len);
end;
var
SavingStream: TFileStream;
i, j: Integer;
begin
SavingStream := TFileStream.Create('SAVE.test', fmCreate or fmOpenWrite or fmShareDenyWrite);
try
WriteIntegerToStream(SavingStream, Length(Categories));
for i := 0 to Length(Categories)-1 do
begin
WriteStringToStream(SavingStream, Categories[i].Name);
WriteIntegerToStream(SavingStream, Categories[i].ID);
WriteBooleanToStream(SavingStream, Categories[i].Default);
WriteIntegerToStream(SavingStream, Length(Categories[i].ChildrenType));
for j := 0 to Length(Categories[i].ChildrenType)-1 do
begin
// write ChildrenType[j] data to SavingStream as needed...
end;
finally
SavingStream.Free;
end;
end;
Run Code Online (Sandbox Code Playgroud)
然后你可以在读回文件时执行类似的操作:
function ReadIntegerFromStream(Stream: TStream): Integer;
begin
Stream.ReadBuffer(Result, Sizeof(Result));
end;
function ReadBooleanFromStream(Stream: TStream): Boolean;
begin
Stream.ReadBuffer(Result, Sizeof(Result));
end;
function ReadStringFromStream(Stream: TStream): String;
var
S: UTF8String;
Len: Integer;
begin
Len := ReadIntegerFromStream(Stream);
SetLength(S, Len);
Stream.ReadBuffer(PAnsiChar(S)^, Len);
Result := String(S);
end;
var
LoadingStream: TFileStream;
i, j: Integer;
begin
LoadingStream := TFileStream.Create('SAVE.test', fmOpenRead or fmShareDenyWrite);
try
i := ReadIntegerFromStream(LoadingStream);
SetLength(Categories, i);
for i := 0 to Length(Categories)-1 do
begin
Categories[i].Name := ReadStringFromStream(LoadingStream);
Categories[i].ID := ReadIntegerFromStream(LoadingStream);
Categories[i].Default := ReadBooleanFromStream(LoadingStream);
j := ReadIntegerFromStream(LoadingStream);
SetLength(Categories[i].ChildrenType, j);
for j := 0 to Length(Categories[i].ChildrenType)-1 do
begin
// read ChildrenType[j] data from LoadingStream as needed...
end;
end;
finally
LoadingStream.Free;
end;
end;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2999 次 |
| 最近记录: |