Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi:在文件中写入/读取变量和记录_Delphi_Record_Delphi Xe8 - Fatal编程技术网

Delphi:在文件中写入/读取变量和记录

Delphi:在文件中写入/读取变量和记录,delphi,record,delphi-xe8,Delphi,Record,Delphi Xe8,在XE8中处理我的项目时,我面临着保存和读取自定义项目文件的必要性,这些文件存储不同类型的变量和记录。 起初,我解决这个问题的方法似乎是可行的,但在实际项目中,它被证明是错误的 我创建文件、存储“类别”记录的方法: 然后读它: var SavingStream: TFileStream; i,j: Integer; begin try SavingStream.ReadBuffer(i,SizeOf(i)); SetLength(Categories,i); for i:=0

在XE8中处理我的项目时,我面临着保存和读取自定义项目文件的必要性,这些文件存储不同类型的变量和记录。 起初,我解决这个问题的方法似乎是可行的,但在实际项目中,它被证明是错误的

我创建文件、存储“类别”记录的方法:

然后读它:

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;
主要问题之一是我不完全理解这种方法背后的逻辑。我的理解是,SizeOf(i)基本上是指获取一个同质文件的某个部分,并将其作为一个变量的值。但是如何存储大小可变的字符串和数组呢?我知道可以在记录本身中限制它的大小,但是我不想限制某些字符串变量

因此,我需要你的建议,我正在使用的方法是否是好的,以及如何使它在我的具体情况下工作。也许有更好的方法来存储这些信息?请记住,我必须存储大量不同的类型,包括图像


Thx提前

您需要将可变长度数据(如字符串)序列化为不包含任何指向其他内存地址的指针的平面格式

试着这样做:

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;
然后,您可以在读回文件时执行类似操作:

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;

您需要将可变长度的数据(如字符串)序列化为不包含任何指向其他内存地址的指针的平面格式

试着这样做:

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;
然后,您可以在读回文件时执行类似操作:

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;

序列化为JSON。或类似的。此时,您正在向磁盘写入指针。写入内存地址。当你把它们读回来的时候,它们没有任何意义。在编写这样的代码之前,您需要做更多的基础工作。您需要了解指针以及字符串是如何实现的等等。序列化为JSON。或类似的。此时,您正在向磁盘写入指针。写入内存地址。当你把它们读回来的时候,它们没有任何意义。在编写这样的代码之前,您需要做更多的基础工作。您需要了解指针以及字符串是如何实现的等等。