Announcement

Collapse
No announcement yet.

File read/write: what am I missing...

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • File read/write: what am I missing...

    Sometimes the simplest things can keep you puzzled...
    I save an array to disk, and then read it again. Somehow the array has 'grown' by one... What am I missing? (or doing wrong?)

    Code:
    #COMPILE EXE "test.exe"
    #DIM ALL
    #INCLUDE "win32api.inc"
    
    Type TestType
      Field1    As Asciiz * 128
      Field2    As Asciiz * 128
      Field3    As Asciiz * 128
      Field4    As Asciiz * 128
    End Type  
    
    Global MyType() As TestType
    
    '==============================================================================
    Function SaveDataFile() As Long                                                             
    '==============================================================================
      Local lCnt As Dword
      ReDim MyType(19)
      Open "test.dat" For Binary As #1
        For lCnt = 0 To Ubound(MyType)
          Put #1 ,, MyType(lCnt)                                                               
        Next lCnt  
      MsgBox "Array upper bound: " & Format$(ubound(MyType)) & $Cr & _
             "File size: " & Format$(Lof(#1)),, "After write"    
      Close #1
    End Function
    
    '==============================================================================
    Function LoadDataFile() As Long                                                            
    '==============================================================================
      Local lCnt As Dword
      Dim MyType(0)
      lCnt = 0                                                                                
      Open "test.dat" For Binary As #2                       
        While IsFalse Eof(#2)                                                                 
          ReDim Preserve MyType(lCnt)                                                           
          Get #2,, MyType(lCnt)                                                          
          If Eof(#2) Then Exit Loop                                             
          Incr lCnt
        Wend       
        MsgBox "Array upper bound: " & Format$(ubound(MyType)) & $Cr & _                                                                           
             "File size: " & Format$(Lof(#2)),, "After read"    
        Close #2                                                                            
    End Function                                                                                
    
    '==============================================================================
    FUNCTION PBMAIN () AS LONG
    '==============================================================================
      SaveDataFile()
      LoadDataFile()
    END FUNCTION
    Regards,
    Peter

  • #2
    I was watching lCnt on your Put and Get lines. When you write the file it goes from 0-19 and when you read it goes from 0-20. Same amount of data but the record number is off by one. So your ubound is one higher.

    Also if you know the size of record (512 bytes), why not use random?

    Comment


    • #3
      Peter try this for load data...
      Code:
      '==============================================================================
      FUNCTION LoadDataFile() AS LONG
      '==============================================================================
        LOCAL lCnt AS DWORD
        DIM MyType(19)
        lCnt = 0
        OPEN "test.dat" FOR BINARY AS #2
          WHILE ISFALSE EOF(#2)
            'ReDim Preserve MyType(lCnt)
            GET #2,, MyType(lCnt)
            IF EOF(#2) THEN EXIT LOOP
            INCR lCnt
          WEND
          MSGBOX "Array upper bound: " & FORMAT$(UBOUND(MyType)) & $CR & _
               "File size: " & FORMAT$(LOF(#2)),, "After read"
          CLOSE #2
      END FUNCTION

      Comment


      • #4
        Might I suggest this method...

        Code:
        #COMPILE EXE "test.exe"
        #DIM ALL
        #INCLUDE "win32api.inc"
        
        '----------------------------------------------------------------------------(')
        
        TYPE TestType
            Field1 AS ASCIIZ * 128
            Field2 AS ASCIIZ * 128
            Field3 AS ASCIIZ * 128
            Field4 AS ASCIIZ * 128
        END TYPE
        
        '----------------------------------------------------------------------------(')
        
        GLOBAL MyType( ) AS TestType
        
        '----------------------------------------------------------------------------(')
        
        FUNCTION SaveDataFile( ) AS LONG
            LOCAL lCnt AS LONG        ' or change to dwCnt AS DWORD?
            LOCAL hFile AS DWORD
            REDIM MyType( 19 )
            hFile = FREEFILE
            OPEN "test.dat" FOR BINARY AS # hFile
            FOR lCnt = LBOUND( MyType ) TO UBOUND( MyType )
                PUT # hFile,, MyType( lCnt )
            NEXT lCnt
            MSGBOX "Array upper bound: " & FORMAT$( UBOUND( MyType )) & $CR & _
                        "File size: " & FORMAT$( LOF( hFile )),, "After write"
            CLOSE # hFile
        END FUNCTION
        
        '----------------------------------------------------------------------------(')
        
        FUNCTION LoadDataFile( ) AS LONG
            LOCAL lCnt AS LONG        ' or change to dwCnt AS DWORD?
            LOCAL lTot AS LONG
            LOCAL hFile AS DWORD
            hFile = FREEFILE
            OPEN "test.dat" FOR BINARY AS # hFile
            lTot = LOF( hFile ) / SIZEOF( TestType )
            REDIM MyType( lTot - 1 )
            FOR lCnt = 0 TO lTot - 1
                GET # hFile, SIZEOF( TestType ), MyType( lCnt )
            NEXT lCnt
            MSGBOX "Array upper bound: " & FORMAT$( UBOUND( MyType )) & $CR & _
                        "File size: " & FORMAT$( LOF( hFile )),, "After read"
            CLOSE #2
        END FUNCTION
        
        '----------------------------------------------------------------------------(')
        
        FUNCTION PBMAIN( ) AS LONG
            SaveDataFile( )
            LoadDataFile( )
        END FUNCTION
         
        <b>George W. Bleck</b>
        <img src='http://www.blecktech.com/myemail.gif'>

        Comment


        • #5
          Yes,

          With a fixed array of course it works...
          But I don't know the size of the file in advance...
          If I read the file until EOF the array should hold 20 items (0:19)

          Why is the EOF loop approach not working?
          Regards,
          Peter

          Comment


          • #6
            The method I posted calculates the number of records in advance based on the record size and the file size; no need to "redim as you go".
            <b>George W. Bleck</b>
            <img src='http://www.blecktech.com/myemail.gif'>

            Comment


            • #7
              Peter,
              The item 20 read in would be the EOF not the data. Right?

              Code:
              '==============================================================================
              FUNCTION LoadDataFile() AS LONG
              '==============================================================================
                LOCAL lCnt AS DWORD
                DIM MyType(19)     'is 0-19????
                lCnt = 0
                OPEN "test.dat" FOR BINARY AS #2
                  WHILE ISFALSE EOF(#2)
                    'ReDim Preserve MyType(lCnt)
                    GET #2,, MyType(lCnt)
                    IF EOF(#2) THEN winbeep(3000, 75): ? STR$(lCnt):EXIT LOOP
                    INCR lCnt
                  WEND
                  MSGBOX "Array upper bound: " & FORMAT$(UBOUND(MyType)) & $CR & _
                       "File size: " & FORMAT$(LOF(#2)),, "After read"
                  CLOSE #2
              END FUNCTION

              Comment


              • #8
                Orig array is 0 to 19, which is 20 elements.
                In LoadDataFile you're DIMing with count which gives 0 to 20, which is 21 elements, Use
                ReDim Preserve MyType(lCnt - 1), that will give 20 elements again.

                Cheers,
                Dale

                Comment


                • #9
                  Not sure why EOF(#2) fails, but if you replace it with the following, it should work.
                  Code:
                       IF SEEK(#2) = LOF(#2) THEN EXIT LOOP

                  Comment


                  • #10
                    Try this with Random. It redims the array before read. Also erase the data before each test.
                    Code:
                    #COMPILE EXE
                    #DIM ALL
                    
                    #INCLUDE "win32api.inc"
                    
                    TYPE TestType
                      Field1    AS ASCIIZ * 128
                      Field2    AS ASCIIZ * 128
                      Field3    AS ASCIIZ * 128
                      Field4    AS ASCIIZ * 128
                    END TYPE
                    
                    GLOBAL MyType() AS TestType
                    
                    '==============================================================================
                    FUNCTION SaveDataFile() AS LONG
                    '==============================================================================
                      LOCAL lCnt AS DWORD
                      REDIM MyType(1 TO 19)
                    
                      OPEN "Test.Dat" FOR RANDOM ACCESS WRITE LOCK WRITE AS #1 LEN = LEN(TestType)
                        FOR lCnt = 1 TO UBOUND(MyType)
                          PUT #1, lCnt, MyType(lCnt)
                        NEXT lCnt
                    
                        MSGBOX "Array upper bound: " & FORMAT$(UBOUND(MyType)) & $CR & _
                               "File size: " & FORMAT$(LOF(#1)),, "After write"
                      CLOSE #1
                    END FUNCTION
                    
                    '==============================================================================
                    FUNCTION LoadDataFile() AS LONG
                    '==============================================================================
                      LOCAL lCnt AS DWORD
                      DIM MyType(0)
                    
                      OPEN "Test.Dat" FOR RANDOM ACCESS READ LOCK WRITE AS #2 LEN = LEN(TestType)
                        REDIM MyType(1 TO LOF(#2)/LEN(TestType))
                    
                        FOR lCnt = 1 TO LOF(#2)/LEN(TestType)
                          GET #2, lCnt, MyType(lCnt)
                        NEXT lCnt
                    
                        MSGBOX "Array upper bound: " & FORMAT$(UBOUND(MyType)) & $CR & _
                             "File size: " & FORMAT$(LOF(#2)),, "After read"
                      CLOSE #2
                    END FUNCTION
                    
                    '==============================================================================
                    FUNCTION PBMAIN () AS LONG
                    '==============================================================================
                      IF ISFILE("Test.Dat") THEN KILL "Test.Dat"
                    
                      SaveDataFile()
                      LoadDataFile()
                    END FUNCTION

                    Comment


                    • #11
                      @Dale:
                      The file is 20 records long, so het LoadDataFile should also be 0 to 19.

                      @Borje:
                      I can use LOF\recordsize as workaround. But I always get a bit uncomfortable if unexpected/unexplainable things happen...
                      Regards,
                      Peter

                      Comment


                      • #12
                        An EOF method of reading would most likely only be used when the data set you are using is unstructured (i.e. random length lines of text). In your case your data is completely structured (i.e. preset length ASCIIZ fields) and would not be suggested to use EOF. You just calculate the number of records and you won't run into an EOF situation.

                        Not sure why you would be uncomfortable as you are actually calculating the reservation based on real world information. If you want to be safer you can ensure the LOF is an even multiple of the record size, and if not then it is fail (more so than EOF), but beyond that it is the most straight forward method.
                        <b>George W. Bleck</b>
                        <img src='http://www.blecktech.com/myemail.gif'>

                        Comment


                        • #13
                          this works...

                          Code:
                          #COMPILE EXE "test.exe"
                          #DIM ALL
                          #INCLUDE "win32api.inc"
                          
                          TYPE TestType
                            Field1    AS ASCIIZ * 128
                            Field2    AS ASCIIZ * 128
                            Field3    AS ASCIIZ * 128
                            Field4    AS ASCIIZ * 128
                          END TYPE
                          
                          GLOBAL MyType() AS TestType
                          
                          '==============================================================================
                          FUNCTION SaveDataFile() AS LONG
                          '==============================================================================
                            LOCAL lCnt AS DWORD
                            REDIM MyType(19)
                            MyType(19).Field1 = "Last data field 1"
                            MyType(19).Field2 = "Last data field 2"
                            MyType(19).Field3 = "Last data field 3"
                            MyType(19).Field4 = "Last data field 4"
                            OPEN "test.dat" FOR BINARY AS #1
                              FOR lCnt = 0 TO UBOUND(MyType)
                                PUT #1 ,, MyType(lCnt)
                              NEXT lCnt
                            MSGBOX "Array upper bound: " & FORMAT$(UBOUND(MyType)) & $CR & _
                                   "File size: " & FORMAT$(LOF(#1)),, "After write"
                            CLOSE #1
                          END FUNCTION
                          
                          '==============================================================================
                          FUNCTION LoadDataFile() AS LONG
                          '==============================================================================
                            LOCAL lCnt AS DWORD
                            DIM MyType(19)     'is 0-19
                            lCnt = 0
                            OPEN "test.dat" FOR BINARY AS #2
                              WHILE ISFALSE EOF(#2)
                                GET #2,, MyType(lCnt)
                                IF EOF(#2) THEN winbeep(3000, 75): ? STR$(lCnt):EXIT LOOP
                                INCR lCnt
                              WEND
                              MSGBOX "Array upper bound: " & FORMAT$(UBOUND(MyType)) & $CR & _
                                   "File size: " & FORMAT$(LOF(#2)),, "After read"
                              CLOSE #2
                          END FUNCTION
                          '==============================================================================
                          FUNCTION PBMAIN () AS LONG
                          '==============================================================================
                            SaveDataFile()
                            LoadDataFile()
                            ? MyType(19).Field1
                            ? MyType(19).Field2
                            ? MyType(19).Field3
                            ? MyType(19).Field4
                          END FUNCTION

                          Comment


                          • #14
                            The filesize is 10240 bytes. But after reading 20 records, LOC returns 10241 BUT EOF is still not set!
                            Seems that somthing isn't quite right ther...
                            Regards,
                            Peter

                            Comment


                            • #15
                              Peter,
                              That is why I said include the " - 1 " in the load function! That is the simplist way (added- in this case) to adjust the count to be the upper bound. (I guess bold and red aren't obvious enough in post 8, so made it 14 point font here.)

                              The only time the count and upper bound are the same is if the lower bound is 1.

                              Cheers,
                              Dale

                              Comment


                              • #16
                                As I said #13 works and the size on disk with data is 10.0 KB (10,240 bytes)

                                Comment


                                • #17
                                  Peter, it is normal behavior.
                                  When you read the last item on disk,
                                  it read sucessfully and there is no EOF() yet.
                                  EOF() will be set when you will try to read past the last item,
                                  then, it's too late, the REDIM is done...

                                  Code:
                                  #COMPILE EXE "Test.exe"
                                  #DIM ALL
                                  #INCLUDE "win32api.inc"
                                  
                                  Type TestType
                                    Field1    As string * 128
                                    Field2    As Asciiz * 128
                                    Field3    As Asciiz * 128
                                    Field4    As Asciiz * 128
                                  End Type
                                  
                                  Global MyType() As TestType
                                  
                                  '==============================================================================
                                  Function SaveDataFile() As Long
                                  '==============================================================================
                                    Local index As Dword
                                    ReDim MyType(19)
                                    Open "test.dat" For Binary As #1
                                    For index = 0 To Ubound(MyType)
                                      Put #1 ,, MyType(index)
                                    Next
                                    SetEof #1 '<<<< To add
                                    MsgBox "Array upper bound: " & Format$(ubound(MyType)) & $Cr & _
                                           "File size: " & Format$(Lof(#1)),, "After write"
                                    Close #1
                                  End Function
                                  
                                  '==============================================================================
                                  Function LoadDataFile() As Long
                                  '==============================================================================
                                    Local index As Dword
                                    Local OneItem As TestType
                                    ReDim MyType(0) 'Use ReDim
                                    index = 0
                                    Open "test.dat" For Binary As #2
                                      Do
                                        IF index > 18 THEN
                                          MSGBOX "EOF determine when the end of a file" & $CRLF & _
                                                 "has been reached WHILE reading its data" & $CRLF & $CRLF & _
                                                 "index is" & STR$(index) & $CRLF & _
                                                 "seek is" & STR$(Seek(#2)) & $CRLF & _
                                                 "loc is" & STR$(LOC(#2)) & $CRLF & _
                                                 "eof is" & STR$(EOF(#2)) & $CRLF & _
                                                 "file size is" & STR$(LOF(#2)) & $CRLF & _
                                                 IIF$(LOC(#2) < LOF(#2), "can read data", "can't read data, Eof() will be triggered with a Beep"), _
                                                 %MB_OK OR %MB_TOPMOST, "Eof() checking"
                                        END IF
                                        Get #2,, OneItem
                                        If Eof(#2) Then Beep : Exit Loop
                                        ReDim Preserve MyType(index)
                                        MyType(index) = OneItem
                                        Incr index
                                      Loop
                                      MsgBox "Array upper bound: " & Format$(ubound(MyType)) & $Cr & _
                                           "File size: " & Format$(Lof(#2)),, "After read"
                                      Close #2
                                  End Function
                                  '==============================================================================
                                  FUNCTION PBMAIN () AS LONG
                                  '==============================================================================
                                    SaveDataFile()
                                    LoadDataFile()
                                  END FUNCTION
                                  '==============================================================================
                                  '

                                  Comment


                                  • #18
                                    Yes, I understand.

                                    Point was that filepointer (LOC) returns 10241 on start last loop, that's clearly past the file's end... But EOF isn't set....
                                    Regards,
                                    Peter

                                    Comment


                                    • #19
                                      You can do 0-19 but the length of file / len of the record is off by one.
                                      Code:
                                      #COMPILE EXE
                                      #DIM ALL
                                      
                                      #INCLUDE "win32api.inc"
                                      
                                      TYPE TestType
                                        Field1    AS ASCIIZ * 128
                                        Field2    AS ASCIIZ * 128
                                        Field3    AS ASCIIZ * 128
                                        Field4    AS ASCIIZ * 128
                                      END TYPE
                                      
                                      GLOBAL MyType() AS TestType
                                      
                                      '==============================================================================
                                      FUNCTION SaveDataFile() AS LONG
                                      '==============================================================================
                                        LOCAL lCnt AS DWORD
                                        REDIM MyType(0 TO 19)
                                      
                                        OPEN "Test.Dat" FOR RANDOM ACCESS WRITE LOCK WRITE AS #1 LEN = LEN(TestType) BASE = 0
                                          FOR lCnt = 0 TO UBOUND(MyType)
                                            PUT #1, lCnt, MyType(lCnt)
                                          NEXT lCnt
                                      
                                          MSGBOX "Array upper bound: " & FORMAT$(UBOUND(MyType)) & $CR & _
                                                 "File size: " & FORMAT$(LOF(#1)),, "After write"
                                        CLOSE #1
                                      END FUNCTION
                                      
                                      '==============================================================================
                                      FUNCTION LoadDataFile() AS LONG
                                      '==============================================================================
                                        LOCAL lCnt AS DWORD
                                        DIM MyType(0)
                                      
                                        OPEN "Test.Dat" FOR RANDOM ACCESS READ LOCK WRITE AS #2 LEN = LEN(TestType) BASE = 0
                                          REDIM MyType(0 TO ((LOF(#2)/LEN(TestType)) -1))
                                      
                                          FOR lCnt = 0 TO ((LOF(#2)/LEN(TestType))-1)
                                            GET #2, lCnt, MyType(lCnt)
                                          NEXT lCnt
                                      
                                          MSGBOX "Array upper bound: " & FORMAT$(UBOUND(MyType)) & $CR & _
                                               "File size: " & FORMAT$(LOF(#2)),, "After read"
                                        CLOSE #2
                                      END FUNCTION
                                      
                                      '==============================================================================
                                      FUNCTION PBMAIN () AS LONG
                                      '==============================================================================
                                        IF ISFILE("Test.Dat") THEN KILL "Test.Dat"
                                      
                                        SaveDataFile()
                                        LoadDataFile()
                                      END FUNCTION

                                      Comment


                                      • #20
                                        Peter, I'm not addressing EOF problem, it's all yours (and everyone elses) to handle!
                                        Dale

                                        Comment

                                        Working...
                                        X