Go Premium for a chance to win a PS4. Enter to Win

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 363
  • Last Modified:

File access with TFileStream

Hey all,

I'm using  a TFileStream to save and load a class to a file.  The following is my class with other records which are used in my class:

------------------------------------------------------------------------------------

type
  THurt = record
    hurt : boolean;
    amount : integer;
  end;

type
  TTileBackgroundProperties = record
    image : integer;
  end;

type
  TTileSpriteProperties = record
    image : integer;
  end;

type
  TSection = record
    enabled : boolean;
    spriteTile : array[1..32,1..24] of TTileSpriteProperties;
    backgroundTile : array[1..32,1..24] of TTileBackgroundProperties;
  end;

type
  TBackgroundImagePath = record
    name, path, section : string;
  end;

type
  TSpriteImagePath = record
    name, path : string;
    walkThrough, bulletThrough : boolean;
    hurt : THurt;
  end;

type
  TMap = class
    private
      password : string; // the password to edit the map
      mapWidth : integer; // in terms of how many sections there are across the map width
      mapHeight : integer; // in terms of how many sections there are down the map height
      backgroundImagePath : array[1..9999] of TBackgroundImagePath;
      spriteImagePath : array[1..9999] of TSpriteImagePath;
      section : array[1..20,1..20] of TSection;
    public
      constructor create(mapWidthIn, mapHeightIn : integer);
      function setupSection : TSection;
      // file handling
      procedure loadFromStream(stream : TStream);
      procedure saveToStream(stream : TStream);
      // sections
      function getSection(x,y : integer) : TSection;
      procedure setSection(x,y : integer; sectionProperties : TSection);
      // background tiles
      function getBackgroundTile(sectionX,sectionY,tileX,tileY : integer) : TTileBackgroundProperties;
      procedure setBackgroundTile(sectionX,sectionY,tileX,tileY : integer; characteristics : TTileBackgroundProperties);
      // sprite tiles
      function getSpriteTile(sectionX,sectionY,tileX,tileY : integer) : TTileSpriteProperties;
      procedure setSpriteTile(sectionX,sectionY,tileX,tileY : integer; characteristics : TTileSpriteProperties);
      // others
      function getMapWidth : integer;
      function getMapHeight : integer;
      procedure setMapWidth(mapWidthIn : integer);
      procedure setMapHeight(mapHeightIn : integer);
      function getPassword : string;
      procedure setPassword(passwordIn : string);
      // image paths
      function getSpriteImagePath(num : integer) : TSpriteImagePath;
      procedure setSpriteImagePath(num : integer; sprite : TSpriteImagePath);
  end;

------------------------------------------------------------------------------------

And here is my load and save procedures in the class:

------------------------------------------------------------------------------------

procedure TMap.loadFromStream(stream : TStream);
// saves the properties to the stream
var
  len : integer;
begin
  { TODO : get map width and height }
  stream.read(len, sizeOf(len)); // get length of password
  setLength(self.password, len); // set length of password
  stream.read(self.password[1], len); // read the password

  stream.Read(self.mapWidth, sizeOf(self.mapWidth)); // get mapWidth
  stream.read(self.mapHeight, sizeOf(self.mapHeight)); // get mapHeight

  stream.read(self.backgroundImagePath, sizeOf(self.backgroundImagePath)); // get background image paths
  stream.read(self.spriteImagePath, sizeOf(self.spriteImagePath)); // get sprite image paths

  stream.read(self.section, sizeOf(self.section)); // get tile
end;

procedure TMap.saveToStream(stream : TStream);
// loads the properties from the stream
var
  len : integer;
begin
  len := length(self.password); // get the length of the password
  stream.write(len, sizeOf(len)); // write length of password
  stream.Write(self.password[1], len); // write the password

  stream.write(self.mapWidth, sizeOf(self.mapWidth)); // set mapWidth
  stream.write(self.mapHeight, sizeOf(self.mapHeight)); // set mapHeight

  stream.write(self.backgroundImagePath, sizeOf(self.backgroundImagePath)); // set background image paths
  stream.write(self.spriteImagePath, sizeOf(self.spriteImagePath)); // set sprite image paths

  stream.write(self.section, sizeOf(self.section)); // write tile
end;

------------------------------------------------------------------------------------

when using these in my main unit i have declared - map : TMap; and thus can access the details of my class.  
In my main unit i save and load the class with the following procedures:

------------------------------------------------------------------------------------

procedure TfrmMain.loadMap;
// loads the modules from the file
var
  fileStream : TStream;
  newItem : TMap;
begin
  fileStream := TFileStream.create(fileName, fmOpenRead); // create the stream
  try
    newItem := TMap.create(mapWidth,mapHeight);
    newItem.loadFromStream(fileStream); // load the map
  finally
    fileStream.free;
  end;
  map := newItem;
end;

procedure TfrmMain.saveMap;
// saves the modules to the file
var
  fileStream : TStream;
begin
  fileStream := TFileStream.create(fileName, fmCreate); // create the stream
  try
    map.saveToStream(fileStream); // save the map
  finally
    fileStream.free;
  end;
end;

------------------------------------------------------------------------------------

Ok so thats my code set up.  Up until about 1 hour ago i was only concerned with the "section : array[1..20,1..20] of TSection;" part of my map class and the loading and saving was working completely fine, my load and save procedures in the class looked like the following:

------------------------------------------------------------------------------------

procedure TMap.loadFromStream(stream : TStream);
// saves the properties to the stream
var
  len : integer;
begin
  stream.read(self.section, sizeOf(self.section)); // get tile
end;

procedure TMap.saveToStream(stream : TStream);
// loads the properties from the stream
var
  len : integer;
begin
  stream.write(self.section, sizeOf(self.section)); // write tile
end;

------------------------------------------------------------------------------------

This worked fine and i could save and load the class and still access my section;  but as soon as i tried to start saving and loading the other parts i started having errors with the loadFromStream & saveToStream at the very top which loads and saves all the details in my class.

Now when i edit my map variable, save close my programme and load it again it works fine if i edit like map.section - but as soon as i edit map.spriteImagePath save and load it it doesn't work.  I get pointer access errors, file access errors And when i display the contents of map.spriteImagePath i get random characters liek characters!  The strings work and integers at the top of the class like the password but spriteImagePath and backgroundImagePath doesn't work.

Any suggestions? sorry i can only offer 25 points it's all ive got left.
0
James_h1023
Asked:
James_h1023
  • 4
  • 2
1 Solution
 
House_of_DexterCommented:
k...Here's your problem

You can Write the SizeOf ...backgroundImagePath and spriteImagePath...

But you Can't Read the SizeOf backgroundImagePath and spriteImagePath...

Why you ask...because they use strings...which is special pointer to an array of chars...so you don't know what the size of your backgroundImagePath and  spriteImagePath

You need to handle any string reads the same way you handled the password and save the len info so that you can read the correct size...
0
 
House_of_DexterCommented:
so something like this in SaveToStream...

var
  iSizeOf: integer  

iSizeOf := sizeOf(self.backgroundImagePath);
stream.write(iSizeOf,SizeOf(iSizeOf));
 stream.write(self.backgroundImagePath, iSizeOf); // set background image paths


...an LoadFromStream add change to something like this...

stream.read(iSizeOf, sizeOf(iSizeOf));
stream.read(self.backgroundImagePath,iSizeOf));
0
 
House_of_DexterCommented:
ignore my last code example...your going to have to store and read the length of each string...because they are dynamic...and sizeof only returns the sizeof the pointer...and not the string...
0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
James_h1023Author Commented:
hmm i see - so maybe because it's a record or strings do i need like a little bit of code to store each string in the record and ten put that in a loop to store the whole array of records?
Can't quite get my head around that - do i need to chagne my load and save procedures in my main unit aswell, cause i would hvae to like construct the map while loading each string bit by bit!
Thakns for helping
0
 
House_of_DexterCommented:
heh...the easy and cheating way is to change string to shortstring...and you don't have to worry about len...the bad...lots of memory useage...255 bytes per Shortstring unless you do something like this var MyString: string[40];

otherwise your going to have to do something like this for each string in a record:

  stream.read(len, sizeOf(len)); // get length of password
  setLength(self.password, len); // set length of password
  stream.read(self.password[1], len); // read the password

and

  len := length(self.password); // get the length of the password
  stream.write(len, sizeOf(len)); // write length of password
  stream.Write(self.password[1], len); // write the password

0
 
James_h1023Author Commented:
oh right yeh - i am dumb
cheers tarly, i think i might set the length to like [40] or something like u suggested.
Thanks a lot, hope to return the favour sometime
James
0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 4
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now