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

Rooster(Posted May) [#1]
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.


GW(Posted May) [#2]
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.


Rooster(Posted May) [#3]
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.


Midimaster(Posted May) [#4]
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.


col(Posted May) [#5]
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?


coffeedotbean(Posted May) [#6]
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




Derron(Posted May) [#7]
@ 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


coffeedotbean(Posted May) [#8]
@Derron - ah yes always pick your Delimiter(s) wisely :p, doesn't have to be single char either.


Henri(Posted May) [#9]
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


Rooster(Posted May) [#10]
@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!