Saving/loading user-defined structures to file?

Xojo is great. But I am used to Visual Basic, where I could just save a whole user-defined structure in to a file with put and then load it with get. I am working on a 2D Game Engine, and have made real progress. Can someone here please kindly advise me on how to efficiently save/load an user defined structure to/from a file?

Thank you!

Dim file As FolderItem Dim fileStream As TextOutputStream file = GetSaveFolderItem("", "MyStruc.txt") If file <> Nil Then fileStream = TextOutputStream.Create(file) fileStream.WriteLine("MyStruc.Element1" + "&" + Str(MyStruc.Element1)) fileStream.WriteLine(("MyStruc.Element2" + "&" + Str(MyStruc.Element2)) fileStream.WriteLine(("MyStruc.Element3" + "&" + Str(MyStruc.Element3)) fileStream.Close End If

I used Str() to convert from any Integers but if your Structure contains only text you can omit that. Ofcourse you have to replace the MyStruc.Elementx with the elements of your structure. I use "&"as a delimiter to distinct the structure name from its contents.

Read in the Xojo documents about writing, appending and reading text files.

You can even use BinaryStream to merge text and binary into a file at read ab-nd write time. Check here.

http://documentation.xojo.com/index.php/Structure

you can write it in one shot

[code]
dim bos as binarystream

       bos.write person.StringValue(False)  [/code] 

reading is similarly easy as you can set a structure using the string value method - but you have to know how much data to read

[code]
dim bos as binaryOutputstream

person.StringValue(False) = bos.read( … )[/code]

And the trick is there is no way to say “as many bytes as the structure holds” - i.e./ sizeof from C
So you need to figure out how to know how many bytes to read
You may also want to write some tagging information into your file so you know what it is (unless its a very rigid format)

So I’d suggest something like

           dim bos as binarystream
           bos.write 'PERS' // a tag so we know whats next is a person structure
           bos.writeInt32 lenb(person.StringValue(False)) // the size so when we read we know how much to read
           bos.write person.StringValue(False)  // the data

then reading becomes simpler

           dim bos as binarystream
           tag = bos.read(4) // read the a tag so we know whats next
           size = bos.readInt32 lenb(person.StringValue(False)) // the size 
           select case tag
                    case 'PERS'
                               person.StringValue(False) = bos.read(size)  // the data
                     case 'other' ….
            end select

Sorry to resurrect the thread - one IMPORTANT item to add to Normans post is to comply with IFF (Interchange File Format, which is what Norman is suggesting), make sure that if you are doing multiple structures (where you have TAG-SIZE-CHUNK;TAG-SIZE-CHUNK, etc. that you align each TAG to a 2 byte boundary. In other words, if your chunk is a odd size, add a pad byte.

I totally understand if this seems nit-picky, and it may be, especially if you are just writing your own files for your use. But any established format that uses “tags” honors the even-boundary byte rule. (Remember, the size is the chunk size, it’s just the following tag must land on a even-boundary offset.) This way you are in-step with the rest of the world, and if you choose to use a parser or parsing library, it’ll be guaranteed compatible.

AFAIK the reason this is, is because of the older Motorola processors required it; 16-bit WORD lengths. And it’s smart to get acquainted with the IFF standard. Basically this thread is about how to create your own file format, and as you can see it’s relatively easy.

Oh, at lastly: if you are mixing Integer types and String types, or have more than one string in a “tag”, you might consider dealing with your strings in a proper way. Your “tag” may contain (for example) INT32 INT32 String INT32. So how do you know the length of your String? It’s hacky to subtract 12 from your chunk size. It’s better if you either have a INT32-STRING where the INT32 is the length of the string, or the PSTRING method where it’s BYTE-STRING (the byte is the string length, of course this is only good for 255-max strings), or NULLTERM where the string ends in a 0 (of course this restricts using NULLS in the string itself). I would recommend the first technique because it has no downsides - and it’s pretty much like what you are doing with tags, only it’s standard to not include pad bytes.

Sorry to overcomplicate the thread but it is good to know this, at least I think.