Prob opening file calling sub function to write, then write from parent function
BlitzMax Forums/BlitzMax Programming/Prob opening file calling sub function to write, then write from parent function
| ||
I've been trying to build a function for saving information from types to files. The problem I ran into is that if I try to write after the function runs, it just comes up as a zero when I read the file. I have tried passing the file name to the function, opening it there, and then reopening to write to it. But for some reason that writes all zeros. Is what I'm trying to do possible? Thanks for reading. |
| ||
First: start using 'Superstrict' at the top of all your programs. Second: It might be easier to build a string for your data and just call the function SaveText() third: Look at the doc under 'streams' to see some simple examples of reading and writing to files. |
| ||
I'm trying to make a function to put in the middle of a "For EachIn" loop, so I don't have to use the same block of code for each variable in the type. Using strings would be more complicated, as I would have to convert them back on reload. And strings don't have a set sizes on the file. |
| ||
I completed your code with the rules of SUPERSTRICT and it runs perfect.SuperStrict Global t%[] Global ex:TStream Global ast% =0 ex = WriteStream ("OOP.dat") t = [4,8,5] ast=SaveData (ex,ast,t) ast:+4 SeekStream (ex,ast) WriteInt (ex,8) CloseStream (ex) ex =ReadStream ("OOP.dat") ast=0 For Local g%=1 To 5 SeekStream (ex,ast) Print "POS" + g% + "=" + ReadInt (ex) ast:+4 Next CloseStream (ex) Function SaveData% (in:TStream Var,pos%,a%[]) Local b%, i% For b=EachIn a.Dimensions() Next For i=0 To b-1 SeekStream (in,pos) WriteInt (in,a [i]) pos:+4 Next Return pos End Function Your only mistake is, that you add 4 to the file pointer before writing the last variable "8". So now your "8" is on position 5. Run my sample to see what I mean. |
| ||
FYI, Using the stream read/write functions automatically advance the file position pointer, so there's no need to use SeekStream in your scenario, unless you intend to use it for some kind of padding? Your code will perform better seeking once ( to a required position ) before your read/write code - assuming you need to seek at all? |
| ||
I would save Type data to a file and read it back as follows; WARNING - not tested. Strict Graphics(640,480) '// Store our band members in a list Global TheBand:TList = New Tlist '// Add some band members AddBandMemeber("John",45,"Guitar") AddBandMemeber("Dave",38,"Drums") AddBandMemeber("James",41,"Keyboard") '// Main Loop Repeat cls if keyhit(KEY_S) SaveBand() if keyhit(KEY_L) LoadBand() if keyhit(KEY_ESCAPE) End flip Forever '// Band member object Type TBandMember Field name:string Field age:Int Field instrument:String Method ExportToStr:String() Return(name+","+age+","+instrument) End Method End Type '// Create a band member (object) and add to the band (list) Function AddBandMemeber:Int(_name:String,_age:Int,_instrument:String) local a:TBandMember = new TBandMember a.name = _name a.age = _age a.instrument = _instrument TheBand.AddLast(a) End Function '// Save all band members as a Delimiter-separated string to a file Function SaveBand:Int() local seperator:String = "|" local band_data:String '// Build the string to save For local a:String = eachin TBandMember.Value() band_data = band_data + a.ExportToStr() + seperator Next '// Save the string file local fileOut:TStream = WriteStream("blah\blah\file.txt") writestring(fileOut, band_data) Closestream(fileOut) End Function '// Load the Delimiter-separated string from a file, then split the string to re-created each band member Function LoadBand:Int() local seperator1:String = "|" local seperator2:String = "," local band_data:String '// Read the file local fileIn:TStream = ReadStream("blah\blah\file.txt") If Not fileIn Then Notify "Cannot find file" ; End band_data = ReadString(fileIn) closeStream(fileIn) '// Print results Print band_data '// Create each band member local member:String[] = band_data.split(seperator1) For local a:Int = 0 until member.length-1 local thisBandMember:String[] = member[a].split(seperator2) AddBandMemeber(thisBandMember[0],Int thisBandMember[1],,thisBandMember[2]) Next End Function |
| ||
@ coffeedotbean Let's hope none of your bandmembers uses an artst name like "The big, big Mr. M". Using delimiters with strings _always_ enforces proper enquoting of the delimiter - and therefor of the the enquoting-string too so here: The big, big Mr. M becomes eg. The big\, big Mr. M To be able to use "\" and "," you need to enquote "\" too, so "\" becomes "\\". How to achieve that? Look how BlitzMax modules handles "~" enquoting. @ saving types Did you consider using Brucey's persistence.mod - it allows to serialize data to XML (and to json). bye Ron |
| ||
@Derron - ah yes always pick your Delimiter(s) wisely :p, doesn't have to be single char either. |
| ||
Hi, you can also use reflection to get type data like: SuperStrict Local me:Person = New Person Print GetObject( me ) Type Person Field name:String = "Henri" Field age:Int = 20 Field instrument:String = "Guitar" EndType Function GetObject:String(obj:Object) If Not obj Then Return Null Local Tid:TTypeId = TTypeId.ForObject(obj) Local Fields:TField[] = TField[](Tid.Fields().ToArray()) Local line:String For Local i:Int = 0 Until Fields.length If i > 0 Then line:+ " ; " line:+ Fields[i].Name() + " = " + String(Fields[i].Get(obj) ) Next Return line EndFunction -Henri |
| ||
@Midimaster That fixed it. Leave it to me to do something like that. lol @col It feels like I used to know that, and then forgot. Probably because most of my read functions check for a non zero at the start of the file, and one early function jumps around in the file a lot. So I probably just got used to using SeekStream by the time I started making save functions. @coffeedotbean That look like a good way to save strings or mixed data. I'll have to remember you and GW's suggestion about that. Thanks for all of your help guys! |