Question

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?

Was it helpful?

Solution

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top