Page 1 of 1

Write\Read Structure()

Posted: Mon Feb 13, 2006 9:41 pm
by localmotion34
i use structures for a ton of stuff, and it would be nice to be able to just pass the address of a structured variable and have PB write the data to the file. then be able to open the file, and read the structure data and have it reassembeld into a working structured variable.

like:

structure test
long.l
string.s
nested.l[30]
another.q
float.d
endstructure

variable.test

variabe\float=0.90909033
variabe\string=getgadgettext(#gadget_editor)

writestructure(#file_0,location)

the procedure could return 0 for an error, but if successful, return the location that you are now in the file.

now: readstructure(#file_0,location, newvariable.test)

debug newvariabe\string

Posted: Tue Feb 14, 2006 9:31 pm
by localmotion34
no one? not anyone would like to see this? wow, am i out in left field or what here.

Posted: Tue Feb 14, 2006 10:19 pm
by Shannara
I could of sworn on these forums, someone had a 3.8x(?) version of code that will step through the members of a structure and write them to file, automatically .. much like your doing. But it may have been lost between the many forum post wipes.

I really dont know if it's possible in PB any more. It would definately ease the read/writing to/from files tremendously in PB.

Posted: Tue Feb 14, 2006 11:09 pm
by Guimauve
All interpreted language, like MatLAB, can do this.

Personnally I prefer to control how my structure is "Write" and "Read" on file. But I agree this task must be done for each Structure you create.

Code: Select all

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< Structure definition >>>>>

Structure Test
   
   long.l
   string.s
   nested.l[30]
   another.q
   float.d 
   
EndStructure

; <<<<<<<<<<<<<<<<<<<<
; <<<<< Mutators >>>>>

Procedure SetTestlong(*ObjectA.Test, long.l)
   
   *ObjectA\long = long
   
EndProcedure

Procedure SetTeststring(*ObjectA.Test, string.s)
   
   *ObjectA\string = string
   
EndProcedure

Procedure SetTestnested(*ObjectA.Test, Index, Value.l)
   
   *ObjectA\nested[Index] = Value
   
EndProcedure

Procedure SetTestanother(*ObjectA.Test, another.q)
   
   *ObjectA\another = another
   
EndProcedure

Procedure SetTestfloat(*ObjectA.Test, float.d)
   
   *ObjectA\float = float
   
EndProcedure

; <<<<<<<<<<<<<<<<<<<<<<<
; <<<<< Observators >>>>>

Procedure.l GetTestlong(*ObjectA.Test)
   
   ProcedureReturn *ObjectA\long
   
EndProcedure

Procedure.s GetTeststring(*ObjectA.Test)
   
   ProcedureReturn *ObjectA\string
   
EndProcedure

Procedure.l GetTestnested(*ObjectA.Test, Index)
   
   ProcedureReturn *ObjectA\nested[Index]
   
EndProcedure

Procedure.q GetTestanother(*ObjectA.Test)
   
   ProcedureReturn *ObjectA\another
   
EndProcedure

Procedure.d GetTestfloat(*ObjectA.Test)
   
   ProcedureReturn *ObjectA\float
   
EndProcedure

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< Read & Write Binary String <<<<<

Procedure WriteBinaryString(FileID.l, string.s)
  
  Length.l = Len(string)
  WriteLong(FileID, Length) 
  WriteData(FileID, @string, Length) 
  
EndProcedure 

Procedure.s ReadBinaryString(FileID.l)
  
  Length.l = ReadLong(FileID)
  string.s = Space(Length)
  ReadData(FileID, @string, Length) 
  
  ProcedureReturn string
EndProcedure 

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< Read Binary file >>>>>

Procedure ReadTest(FileID.l, *ObjectA.Test)
   
   SetTestlong(*ObjectA, ReadLong(FileID))
   SetTeststring(*ObjectA, ReadBinaryString(FileID))
   
   For Index = 0 To 29
      SetTestnested(*ObjectA, Index, ReadLong(FileID))
   Next
   
   SetTestanother(*ObjectA, ReadQuad(FileID))
   SetTestfloat(*ObjectA, ReadDouble(FileID))
   
EndProcedure

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< Write Binary file >>>>>

Procedure WriteTest(FileID.l, *ObjectA.Test)
   
   WriteLong(FileID, GetTestlong(*ObjectA))
   WriteBinaryString(FileID, GetTeststring(*ObjectA))
   
   For Index = 0 To 29
      WriteLong(FileID, GetTestnested(*ObjectA, Index))
   Next
   
   WriteQuad(FileID, GetTestanother(*ObjectA))
   WriteDouble(FileID, GetTestfloat(*ObjectA))
   
EndProcedure

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< Code generated in : 31 ms <<<<<
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
Also, if you wish to save a mixed field type structure, like in your exemple, an implicit information must be written to the file (the string lenght). This is why I have created these following procedures.

Code: Select all

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< Read & Write Binary String <<<<<

Procedure WriteBinaryString(FileID.l, string.s)
  
  Length.l = Len(string)
  WriteLong(FileID, Length) 
  WriteData(FileID, @string, Length) 
  
EndProcedure 

Procedure.s ReadBinaryString(FileID.l)
  
  Length.l = ReadLong(FileID)
  string.s = Space(Length)
  ReadData(FileID, @string, Length) 
  
  ProcedureReturn string
EndProcedure 
Other wise you will not be able to read the string from the file.

Anyways If Fred can achieve the goal to generate a procedure to Write and Read any Structure on binary file it can be greate.

Best Regards

Guimauve

Posted: Sat May 20, 2006 6:59 pm
by jonljacobi
I'd love this as well.

Cheers, Jon

Posted: Tue Jun 05, 2007 2:22 pm
by Prof
I second that. I have already e-mailed this request to Fred.

I think what is required is a GET & PUT command to read and create records in a file. The FileSeek command could be used as an index to the pointer in the file. Or maybe even a RECORDSEEK command to jump from record to record withough having to keep tabs on the file pointer with the Fileseek command.

example....

Code: Select all

Structure Student
    Fornames.s{30}
    Surname.s{25} 
    DOB_DD.s{2}
    DOB_MM.s{2}
    DOB_YY.s{2}
EndStructure

Dim Student_Array.Student(100)

Index=0
Student_Array(0)=Get(FileID,Index)
Would read a structure (one record) from FILEID at point INDEX and load it straight into the structure in the Student_Array at element 0.

This would be really handy to have but would only probably work with fixed length records (which I only use anyway).

I am currently trying to create my own workaround for the time being.

Posted: Tue Jun 05, 2007 6:15 pm
by Fred
For such structure, you can use:

Code: Select all

WriteData(#File, Variable.YourStruct, @SizeOf(YourStruct)
The structure should not contain any regular strings (.s)

Posted: Wed Jun 06, 2007 3:13 am
by Guimauve
Fred wrote:For such structure, you can use:

Code: Select all

WriteData(#File, Variable.YourStruct, @SizeOf(YourStruct)
The structure should not contain any regular strings (.s)
This is true only if you don't need to modify in any following version. For exemple the 1st version of the structure is :

Code: Select all

Structure Student
    Fornames.s{30}
    Surname.s{25}
    DOB_DD.s{2}
    DOB_MM.s{2}
    DOB_YY.s{2}
EndStructure
But the 2nd version of the structure is :

Code: Select all

Structure Student
    Fornames.s{60}
    Surname.s{50}
    DOB_DD.s{6}
    DOB_MM.s{6}
    DOB_YY.s{6}
EndStructure
After this update you will not be able to load the old version anymore with ReadData().

Anyway if you are sure about your structure definition you can use Read/Write Data without any problems. But in my point of view it's not a safe way to save string in a binary file.

If you need to have a regular string (.s) in your stucture the only way to do the gob it's something like this :

Code: Select all

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< Structure declaration <<<<<

Structure Student
  
  Fornames.s
  Surname.s
  DOB_DD.s
  DOB_MM.s
  DOB_YY.s
  
EndStructure

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< Read binary file operator <<<<<

Procedure ReadStudent(FileID.l, *StudentA.Student)
  
  *StudentA\Fornames = Space(ReadLong(FileID))
  ReadData(FileID, @*StudentA\Fornames, Len(*StudentA\Fornames))
  *StudentA\Surname = Space(ReadLong(FileID))
  ReadData(FileID, @*StudentA\Surname, Len(*StudentA\Surname))
  *StudentA\DOB_DD = Space(ReadLong(FileID))
  ReadData(FileID, @*StudentA\DOB_DD, Len(*StudentA\DOB_DD))
  *StudentA\DOB_MM = Space(ReadLong(FileID))
  ReadData(FileID, @*StudentA\DOB_MM, Len(*StudentA\DOB_MM))
  *StudentA\DOB_YY = Space(ReadLong(FileID))
  ReadData(FileID, @*StudentA\DOB_YY, Len(*StudentA\DOB_YY))
  
EndProcedure

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< Write binary file operator <<<<<

Procedure WriteStudent(FileID.l, *StudentA.Student)
  
  WriteLong(FileID, Len(*StudentA\Fornames))
  WriteData(FileID, @*StudentA\Fornames, Len(*StudentA\Fornames))
  WriteLong(FileID, Len(*StudentA\Surname))
  WriteData(FileID, @*StudentA\Surname, Len(*StudentA\Surname))
  WriteLong(FileID, Len(*StudentA\DOB_DD))
  WriteData(FileID, @*StudentA\DOB_DD, Len(*StudentA\DOB_DD))
  WriteLong(FileID, Len(*StudentA\DOB_MM))
  WriteData(FileID, @*StudentA\DOB_MM, Len(*StudentA\DOB_MM))
  WriteLong(FileID, Len(*StudentA\DOB_YY))
  WriteData(FileID, @*StudentA\DOB_YY, Len(*StudentA\DOB_YY))
  
EndProcedure

; <<<<<<<<<<<<<<<<<<<<<<<
; <<<<< END OF FILE <<<<<
; <<<<<<<<<<<<<<<<<<<<<<<
Regards
Guimauve