Reading tabled data
BlitzMax Forums/BlitzMax Beginners Area/Reading tabled data| 
 | ||
| I've asked this question before, but at that time there wasn't a ready answer.  Consequently, I had decided to wait until the full version was released with documentation.  However, today after downloading the most recent update I noticed the stdc module, which includes fopen but not fscanf or fprintf.  Anyway with some two months having passed, is there an easy way to read tabled data into a struct? | 
| 
 | ||
| what exactly do you mean by tabled data? perhaps you can give an example of the file you want to read? | 
| 
 | ||
| Take the following as an example, -- smith 34 160 jones 26 176 blake 29 166 --- In C, #define MAXRECORDS 100 typedef struct { char name[30]; int age; int height; }DATA; DATA *users = malloc(MAXRECORDS * sizeof(DATA)); then read the file so that individual records can be easily accessed using a numerical index. I use fscanf in this case and fprintf for the opposite. These functions have made it relatively easy to manage my data in C. As Blitzmax evolves I wouldn't mind migrating. | 
| 
 | ||
| hmmm. I thought someone might have given you a good answer, as I think there might be a clever solution to this.. But from what I can gather, you should be able to do the same thing in 'Max relatively easy.. Say using banks or (RAM)streams... | 
| 
 | ||
| [edit] DOH! Not what you asked :D Something like this, might work: Const MAXRECORDS = 100 Type Data Field name:String Field age:Int Field height:Int Method WhoIs() Print "Name: "+self.name+", Age: "+self.age+", Height: "+self.height+"cm" EndMethod EndType Local users:Data[MAXRECORDS] For Local i = 0 Until MAXRECORDS users[i] = New Data users[i].name = "Bob "+i users[i].age = Rand(0,100) users[i].height = Rand(100,200) Next users[10].WhoIs() users[45].WhoIs() users[89].WhoIs()You wouldn't need a max number of records, as you can easily resize the array if you need to. | 
| 
 | ||
| Ok, I assume you will want to read the file, which has certain seperators to show, when a new entry is there? So something like this should work: 
Function ReadDString:String(stream:TStream,seperator:Byte[])
 If stream = Null
  Return ""
 EndIf
 Local b:byte
 Local s:String
 While Eof(stream) = False
  b = ReadByte(stream)
  For Local i = 0 Until seperator.length
   If b = seperator[i]
    Return s
   EndIf
  Next
  s :+ Chr(b)
 Wend
End FunctionYou then need to open a file, and supply that and a list of seperator values to it...Something like this: myfile = ReadFile("hello.txt")
Repeat
 Local s:string = ReadDString(myfile,[Asc(" "),10])
 Print s
Until s = ""
CloseFile(myfile)It's not tested, so it might be buggy :) | 
| 
 | ||
| Thank you for the examples. I tend to use space separated variables and read until not EOF. I believe that fscanf is flexible in that the number of spaces dosn't matter. Hardcoding the separator would be less tolerant in this case. | 
| 
 | ||
| I've created some code for you (with comments): 
Type Data
	Global DataArray:Data[]
	Field Name$
	Field Age%
	Field Height%
	Function ReadTabledData(DFH%)
		Local LineFromFile$ = ReadLine$(DFH%) ' Read a line from the given filehandle
		Local a:Data = New Data ' Create a new "Data"-object
		' Store the name without ending spaces
		a.Name$ = LineFromFile$[..10] ' Copy the first 10 characters from the line into field Name$ (0..9)
		' Remove spaces at the end of the name
		While Chr(a.Name$[a.Name$.length - 1]) = Chr(32)
			a.Name$ = a.Name$[..(a.Name$.length - 1)]
		Wend
		a.Age% = Int(LineFromFile$[10..15]) ' Copy the characters 10..14 to the Age-field and convert to Int
		a.Height% = Int(lineFromFile$[15..20]) ' Copy characters 15..19 to the Height-field and convert to Int
		' Resize the array to hold one more object
		DataArray = DataArray[..(DataArray.length + 1)]
		' Add the new Data-object to the array
		DataArray[DataArray.length - 1] = a
	End Function
End Type
' Open a file for reading (DFH = DataFileHandle)
Local DFH% = ReadFile("c:\Test.txt")
' Keep reading until EndOfFile
While Not Eof(DFH%)
	Data.ReadTabledData(DFH%)
Wend
' Close the file
CloseFile(DFH%)
' Print all names and ages
For i = 0 Until Data.DataArray.length
	Print "Name = " + Chr(34) + Data.DataArray[i].Name$ + Chr(34)
	Print "    Age = " + Chr(34) + Data.DataArray[i].Age% + Chr(34)
	Print "    Height = " + Chr(34) + Data.DataArray[i].Height% + Chr(34)
	Print
Next
End
File Test.txt: Johnny 20 185 Piet 27 170 Geert 26 182 Gert 28 120 Cornelis 50 150 |