User Tools

Site Tools


reading_20and_20writing_20arrays_20in_20files

This is an old revision of the document!


Reading and writing arrays in files

by Jon Ripley, May 2011

Alternative method added by Steve Drain, Oct 2013

BBC BASIC for Windows does not provide a simple method of writing arrays to a file and reading them back again, doing so traditionally requires looping through the array and saving each separate item individually.

The PROC_ReadArray and PROC_WriteArray routines below provide equivalents to PRINT# and INPUT# for arrays and are faster than the traditional method in most cases.

      PROC_WriteArray(fileHandle%, ^array())
      PROC_ReadArray(fileHandle%, ^array())


When reading and writing arrays you must prefix the array variable name with the address of operator, the ^ symbol, this allows us to pass all types of array to a single routine rather than requiring a separate routine for each.

PROC_WriteArray writes the contents of an array to the file specified by fileHandle%.

      DIM array(9, 9, 9, 9)
      REM Initialise array
      fileHandle% = OPENOUT("data.dat")
      PROC_WriteArray(fileHandle%, ^array())
      CLOSE#fileHandle%


PROC_ReadArray reads data from the file specified by fileHandle% and stores it in the specified array.

      DIM array(1000, 10)
      fileHandle% = OPENIN("data.dat")
      PROC_ReadArray(fileHandle%, ^array())
      CLOSE#fileHandle%


For more information about PROC_SwapMemory see swapping the contents of two areas of memory.

The full code for PROC_ReadArray, PROC_WriteArray and PROC_SwapMemory is as follows:

      DEF PROC_WriteArray(file%, parr%):LOCAL write%:write%=TRUE
      DEF PROC_ReadArray(file%, parr%):LOCAL write%
      LOCAL i%, tele%, esize%, temp%
      IF NOT (parr%?-1 = 0 AND parr%?-2 = 40) THEN
        ERROR 6, "Type mismatch: Bad array pointer"
        ENDPROC
      ENDIF
      tele%=1
      FOR i%=0 TO ?!parr%-1
        tele%*=!((!parr%+1)+(4*i%))
      NEXT i%
      CASE parr%?-3 OF
        WHEN ASC"%":esize%=4
        WHEN ASC"#":esize%=8
        WHEN ASC"$":esize%=6
        WHEN ASC"&":esize%=1
        OTHERWISE:esize%=5
      ENDCASE
      PTR#file%=PTR#file%
      IF parr%?-3 <> ASC"$" THEN
        IF write% THEN
          SYS "WriteFile", @hfile%(file%), !parr%+1+?!parr%*4, tele%*esize%, ^temp%, 0
        ELSE
          SYS "ReadFile", @hfile%(file%), !parr%+1+?!parr%*4, tele%*esize%, ^temp%, 0
        ENDIF
      ELSE
        LOCAL temp$()
        DIM temp$(tele%-1)
        PROC_SwapMemory(!^temp$()+1+?!^temp$()*4, !parr%+1+?!parr%*4, tele%*esize%)
        IF write% THEN
          FOR i%=0 TO tele%-1:PRINT#file%, temp$(i%):NEXT i%
        ELSE
          FOR i%=0 TO tele%-1:INPUT#file%, temp$(i%):NEXT i%
        ENDIF
        PROC_SwapMemory(!^temp$()+1+?!^temp$()*4, !parr%+1+?!parr%*4, tele%*esize%)
      ENDIF
      ENDPROC
      REM PROC_SwapMemory(addr1%, addr2%, size%)
      REM Suggested by Richard Russell
      DEF PROC_SwapMemory(B%, D%, C%)
      PRIVATE memswap
      IF memswap=0 THEN
        LOCAL P%
        DIM memswap 10
        P%=memswap
        [OPT 2
        mov al,[ebx]
        xchg al,[edx]
        mov [ebx],al
        inc ebx
        inc edx
        loop memswap
        ret
        ]
      ENDIF
      CALL memswap
      ENDPROC
 


Thanks to Richard Russell for the SwapMemory function.


Alternative method


This method writes information about the type of array and its size in the file and checks that it it the same when reading. It does not require the SwapMemory assembler code.

The API is the same as the routines above, except, when reading:

  • the number of elements in the target array must be equal to the file array, but the array can be a different shape
  • a string target array must be empty


      DEF PROC_WriteArray(file%,pntr%)
      LOCAL type%,size%,numb%,temp%
      PROC_ArrayData
      BPUT#file%,type%
      REM write the number of elements as a word
      BPUT#file%,numb%
      BPUT#file%,numb%>>8
      BPUT#file%,numb%>>16
      BPUT#file%,numb%>>24
      REM flush the buffer
      PTR#file%=PTR#file%
      IF type%=ASC"$" THEN
        FOR pntr%=pntr% TO pntr%+numb%*size%-1 STEP size%
          BPUT#file%,pntr%?4
          BPUT#file%,pntr%?5
          size%=pntr%?4+(pntr%?5<<8)
          PTR#file%=PTR#file%
          SYS"WriteFile", @hfile%(file%),pntr%,size%,^temp%,0
        NEXT pntr%
      ELSE
        SYS"WriteFile", @hfile%(file%),pntr%,numb%*size%,^temp%,0
      ENDIF
      ENDPROC
      DEF PROC_ReadArray(file%,pntr%)
      LOCAL type%,size%,numb%,temp%
      PROC_ArrayData
      IF type%<>BGET#file% THEN ERROR 6,"Wrong array type"
      REM read the number of elements as a word
      temp%=BGET#file%
      temp%+=BGET#file%<<8
      temp%+=BGET#file%<<16
      temp%+=BGET#file%<<24
      IF numb%<>temp% THEN ERROR 6,"Wrong array size"
      REM flush the buffer
      PTR#file%=PTR#file%
      IF type%=ASC"$" THEN
        FOR pntr%=pntr% TO pntr%+numb%*size%-1 STEP size%
          IF pntr%?4 OR pntr%?5 THEN ERROR 6,"String array not empty"
          pntr%?4=BGET#file%
          pntr%?5=BGET#file%
          size%=pntr%?4+(pntr%?5<<8)
          DIM !pntr% size%
          PTR#file%=PTR#file%
          SYS"ReadFile", @hfile%(file%),pntr%,size%,^temp%,0
        NEXT pntr%
      ELSE
        SYS"ReadFile",@hfile%(file%),pntr%,numb%*size%,^temp%,0
      ENDIF
      ENDPROC
      DEF PROC_ArrayData
      IF pntr%?-2<>ASC"(" THEN ERROR 6,"Not an array"
      type%=pntr%?-3
      CASE type% OF
        WHEN ASC"%":size%=4
        WHEN ASC"#":size%=8
        WHEN ASC"$":size%=6
        WHEN ASC"&":size%=1
        OTHERWISE:type%=ASC"|":size%=5
      ENDCASE
      pntr%=!pntr%
      numb%=1
      FOR temp%=pntr%+1 TO pntr%+?pntr%*4 STEP 4
        numb%*=!temp%
      NEXT temp%
      pntr%=temp%
      ENDPROC
This website uses cookies for visitor traffic analysis. By using the website, you agree with storing the cookies on your computer.More information
reading_20and_20writing_20arrays_20in_20files.1522502376.txt.gz · Last modified: 2018/03/31 13:19 by 127.0.0.1