I am trying to write and read a non-fixed string using TFileStream. I am getting an access violation error though. Here is my code:
// Saving a file
(...)
count:=p.Tags.Count; // Number of lines to save (Tags is a TStringList)
FS.Write(count, SizeOf(integer));
for j := 0 to p.Tags.Count-1 do
begin
str:=p.Tags.Strings[j];
tmp:=Length(str)*SizeOf(char);
FS.Write(tmp, SizeOf(Integer));
FS.Write(str[1], Length(str)*SizeOf(char));
end;
// Loading a file
(...)
p.Tags.Add('hoho'); // Check if Tags is created. This doesn't throw an error.
Read(TagsCount, SizeOf(integer)); // Number of lines to read
for j := 0 to TagsCount-1 do
begin
Read(len, SizeOf(Integer)); // length of this line of text
SetLength(str, len); // don't know if I have to do this
Read(str, len); // No error, but str has "inaccessible value" in watch list
p.Tags.Add(str); // Throws error
end;
The file seems to save just fine, when I open it with a hexeditor, I can find the right strings saved there, but loading is throwing errors.
Could you help me out?
You save the number of bytes, and that's how many bytes you write. When you read the value, you treat it as the number of characters, and then read that many bytes. That won't cause the problem you're seeing now, though, since you're making the buffer bigger than it needs to be as of Delphi 2009.
The problem is that you're reading into the string variable, not the string's contents. You used str[1]
when writing; do the same when reading. Otherwise, you're overwriting the string reference that you allocated when you called SetLength
.
Read(nBytes, SizeOf(Integer));
nChars := nBytes div SieOf(Char);
SetLength(str, nChars);
Read(str[1], nBytes);
And yes, you do need to call SetLength
. Read
doesn't know what its reading into, so it has no way of knowing that it needs to set the size to anything in advance.