更新时间:2023-02-02 21:32:03
不要使用包含正常的字符串记录缓冲区操作。相反 ShortString短
,字符串
是唯一的指向字符串内容。所以,你的code保存和加载唯一的指向字符串的内容,而不是字符串。如果装载值指向不可访问内存即可获得访问冲突。
更改code分开保存和记录加载变量,像这样的:
类型
TmyRec =记录
STR:字符串;
我:整数;
程序SaveToStream(流:TStream);
程序LoadFromStream(流:TStream);
结束;{} myRec程序TmyRec.LoadFromStream(流:TStream);
VAR
STRLEN:整数;
STRBUF:TB的;
开始
Stream.Read(STRLEN,一下SizeOf(整数));
SetLength函数(STRBUF,strlen的);
Stream.Read(STRBUF,strlen的); STR:= TEncoding.UTF8.GetString(STRBUF); Stream.Read(我,一下SizeOf(整数));
结束;程序TmyRec.SaveToStream(流:TStream);
VAR
STRBUF:TB的;
STRLEN:整数;
开始
//直集编码类型有助于避免不同平台的问题。
//例如,Windows使用UCS2,Android和iOS - UTF8编码
STRBUF:= TEncoding.UTF8.GetBytes(STR);
STRLEN:=长度(STRBUF); Stream.Write(STRLEN,一下SizeOf(整数));
Stream.Write(STRBUF,strlen的);
Stream.Write(我,一下SizeOf(整数));
结束;
更新:
你了解泛型?相反,动态数组,你可以使用从TList并加载/保存记录的:
类型
TmyRecList =等级(从TList< TmyRec>)
上市
程序SaveToStream(流:TStream);
程序LoadFromStream(流:TStream);
结束;{} TmyRecList程序TmyRecList.LoadFromStream(流:TStream);
VAR
莱恩:整数;
我:整数;
REC:TmyRec;
开始
明确; Stream.Read(LEN,一下SizeOf(整数)); 对于i:= 0至莱恩-1做
开始
Rec.LoadFromStream(流);
添加(REC);
结束;
结束;程序TmyRecList.SaveToStream(流:TStream);
VAR
我:整数;
开始
Stream.Write(计数,一下SizeOf(整数));
对于i:= 0开始计数1做
项目[I] .SaveToStream(流);
结束;程序THeaderFooterForm.FormCreate(发件人:TObject的);
VAR
流:TStream;
REC:TmyRec;
recList:TmyRecList;
开始
流:= TMemoryStream.Create;
尝试
recList:= TmyRecList.Create;
尝试
rec.str:='示范文本;
rec.i:= 123;
recList.Add(REC); rec.str:='其他文本';
rec.i:= 234;
recList.Add(REC); recList.SaveToStream(流);
Stream.Seek(0,soBeginning); recList.LoadFromStream(流);
ShowMessage('这是第二个记录STR值:'+ recList [1]名为.str);
最后
recList.Free;
结束;
最后
Stream.Free;
结束;
I think this will look like 'do my homework' kind of a question, but I'm still at the 'copy code, use it and try to understand it' phase, and this is the most active thing I know of for posting questions of this theme.
I have a record:
type
Card = record
Name: string;
Up,Right,Left,Down,Mark: Single;
IDNumber: Integer;
end;
And array of that record:
var
ArrayCard: array of Card;
And I wanted to know how can a dynamic array of this kind be stored/loaded to/from a file.
Tried using this piece of code: http://www.pascalgamedevelopment.com/showthread.php?6319-save-load-a-dynamic-array like this:
Procedure TMainFrom.WriteMyData;
Var
FS : TFileStream;
I,iSize : Integer;
TmpPath: string;
Begin
TmpPath:= TPath.Combine(TPath.GetDocumentsPath, 'Cards.dat');
FS := TFileStream.Create(TmpPath, fmOpenWrite);
iSize:= Length(ArrayCard);
FS.WriteBuffer(iSize,SizeOf(iSize));
For I := 0 To iSize - 1 Do
FS.WriteBuffer(ArrayCard[I],SizeOf(Card));
FS.Free;
End;
An it seems to work so far, but then I try to load it like this:
Procedure TMainFrom.ReadMyData;
Var
FS : TFileStream;
I,iSize : Integer;
TmpPath: string;
TempCard : Card;
Begin
TmpPath:= TPath.Combine(TPath.GetDocumentsPath, 'Cards.dat');
FS := TFileStream.Create(TmpPath, fmOpenRead);
FS.ReadBuffer(iSize,SizeOf(iSize));
SetLength(ArrayCard,iSize);
For I := 0 To iSize - 1 Do
Begin
FS.ReadBuffer(TempCard,SizeOf(Card));
ArrayCard[I] := TempCard; //It Breaks Here...The Watch List: TempCard Inaccessible value
End;
FS.Free;
End;
And I get a Exception EAccessViolation in module...
Then I also tried something like this: delphi Save and Load dynamic array It loads the array with the correct amount of items, but they are all empty or blank:
procedure TMainFrom.SaveCardsToFile;
var
Stream: TStream;
L: Integer;
TmpPath: string;
ICount: Integer;
strm: TMemoryStream;
begin
TmpPath:= TPath.Combine(TPath.GetDocumentsPath, 'Cards.bin');
Stream:= TFileStream.Create(TmpPath, fmCreate);
L:= Length(ArrayCard);
Stream.WriteBuffer(L, SizeOf(L));
Stream.WriteBuffer(Pointer(ArrayCard)^, L * SizeOf(Card));
Stream.Free;
end;
procedure TMainFrom.LoadCardsFromFile;
var
Stream: TStream;
L: LongWord;
TmpPath: string;
begin
TmpPath:= TPath.Combine(TPath.GetDocumentsPath, 'Cards.bin');
Stream:= TFileStream.Create(TmpPath, fmOpenRead);
Stream.ReadBuffer(L, SizeOf(L));
SetLength(ArrayCard, L);
Stream.ReadBuffer(Pointer(ArrayCard)^, L * SizeOf(Card));
Stream.Free;
end;
Do not use buffer operations with records which contains "normal" strings. Instead of shortstring
, string
is only pointer to string content. So, your code saves and loads only pointer to string content, not string. You can get Access Violation if loaded value points to unreachable memory.
Change your code to separately save and load variables in record, like this:
type
TmyRec = record
str: string;
i: integer;
procedure SaveToStream(Stream: TStream);
procedure LoadFromStream(Stream: TStream);
end;
{ myRec }
procedure TmyRec.LoadFromStream(Stream: TStream);
var
strLen: integer;
strBuf: TBytes;
begin
Stream.Read(strLen, SizeOf(Integer));
SetLength(strBuf, strLen);
Stream.Read(strBuf, strLen);
str:=TEncoding.UTF8.GetString(strBuf);
Stream.Read(i, SizeOf(Integer));
end;
procedure TmyRec.SaveToStream(Stream: TStream);
var
strBuf: TBytes;
strLen: integer;
begin
// direct set encoding type helps to avoid problems with different platforms.
// for example, Windows uses UCS2, Android and iOS - UTF8 encoding
strBuf:=TEncoding.UTF8.GetBytes(str);
strLen:=Length(strBuf);
Stream.Write(strLen, SizeOf(Integer));
Stream.Write(strBuf, strLen);
Stream.Write(i, SizeOf(Integer));
end;
Update: do you read about generics? Instead of dynamic array, you can use TList and load/save records in it:
type
TmyRecList = class(TList<TmyRec>)
public
procedure SaveToStream(Stream: TStream);
procedure LoadFromStream(Stream: TStream);
end;
{ TmyRecList }
procedure TmyRecList.LoadFromStream(Stream: TStream);
var
Len: integer;
i: Integer;
rec: TmyRec;
begin
Clear;
Stream.Read(Len, SizeOf(integer));
for i := 0 to Len-1 do
begin
Rec.LoadFromStream(Stream);
Add(rec);
end;
end;
procedure TmyRecList.SaveToStream(Stream: TStream);
var
i: Integer;
begin
Stream.Write(Count, SizeOf(Integer));
for i := 0 to Count-1 do
Items[i].SaveToStream(Stream);
end;
procedure THeaderFooterForm.FormCreate(Sender: TObject);
var
Stream: TStream;
rec: TmyRec;
recList: TmyRecList;
begin
Stream:=TMemoryStream.Create;
try
recList:=TmyRecList.Create;
try
rec.str:='sample text';
rec.i:=123;
recList.Add(rec);
rec.str:='another text';
rec.i:=234;
recList.Add(rec);
recList.SaveToStream(Stream);
Stream.Seek(0, soBeginning);
recList.LoadFromStream(Stream);
ShowMessage('this is str value in second record: ' + recList[1].str);
finally
recList.Free;
end;
finally
Stream.Free;
end;