Jump to content

QBasic/Files

From Wikibooks, open books for an open world

In this lesson, we will learn how to create and modify files. In doing so, we will create a portion of a text editor to handle reading and writing files to and from disk - the program won't be complete by the end of this chapter, but will be finished within Advanced Text Output.

Let's start by setting up out main procedure:

'$DYNAMIC
ON ERROR GOTO handler ' Prepares the error handler
DIM text(50) AS STRING ' Used to contain the text file.
maxlines = 50 ' Contains the current size of the buffer.

DO
  CLS 'clears the screen
  INPUT "Would you like to create a (N)ew file, (L)oad an existing one, or (E)xit the program"; choice$

  SELECT CASE UCASE$(choice$) 'UCASE$ converts strings to UPPER CASE
    CASE "N" 'New file
    CASE "L" 'Load a file
    CASE "E" 'Exit
      CLS
      END
  END SELECT
LOOP 'returns to the top of the program.

handler:
errorflag = ERR  ' Keep track of the error that occurred.
RESUME NEXT ' Proceeds with the next statement.

As you can see, we are using CASE rather than IF. IF statements can sometimes work better than case statements, but for now, we want to avoid spaghetti code (where there are too many GOTO's).

So far, we don't really have much, but it's a start. We've asked the user what they want to do, and finished 1/3 options. Not so shabby when you put it that way!

The OPEN statement

[edit | edit source]

The open statement allows either reading or writing information from the disk. In general, the open statement follows this pattern:

OPEN file$ FOR INPUT AS 1
OPEN file$ FOR OUTPUT AS 2

The file$ determines the filename to use. The FOR portion indicates how the file will be accessed or operated - it may be APPEND, BINARY, INPUT, OUTPUT, and RANDOM. The AS # is the identifier used for the file handle in question - this may be a variable if desired.

Note:
If you allow the user to enter a filename that does not exist on disk, you need to implement error handling using ON ERROR to react to this situation.

Input and output

[edit | edit source]

When you need to access or write content to a file handle, the PRINT and INPUT statements expect a file handle to appear as the first parameter:

 INPUT #1, a$
 PRINT #2, a$

In some cases, you need to detect if you are going to reach the end of file - this is performed by the EOF function, which accepts a filehandle that takes input.

Reading the file from disk

[edit | edit source]

We will now add a subroutine to read the complete file from disk, as lines of text, into an string array called text(). It is also possible to read a data file full of numerical values (and input these into a number array), however that is a different topic.

Note the code that finds the file 'size', by reading lines one at a time until the End Of File is reached, and the use of 'SEEK' to 'rewind' to the beginning again.

SUB LoadFile
  SHARED filename$
  SHARED lines, maxlines
  SHARED text() AS STRING
  SHARED errorflag
    
  INPUT "Enter filename: "; filename$

  OPEN filename$ FOR INPUT AS 1
  IF errorflag <> 0 THEN
    errorflag = 0
    CLOSE
    PRINT "File not found - press return to continue."
    INPUT "", a$
    EXIT SUB
  END IF

  ' Count the number of lines.
  lines = 0
  DO WHILE NOT EOF(1)
    LINE INPUT #1, l$
    lines = lines + 1
  LOOP

  'Allocate enough space for input. 
  IF maxlines > lines THEN
    REDIM text(lines + 25) AS STRING
    maxlines = lines + 25
  END IF
  SEEK #1, 1 ' Rewind to the beginning of the file.

  ' Read the lines into the buffer
  FOR cline = 1 TO lines
    LINE INPUT #1, text(cline)
  NEXT
  CLOSE 1
  errorflag = 0

END SUB

The example above treats the file as type=text. If the file contains numbers (for example, a data array of N integers per line x M lines) these can be read (input #) one at a time, directly into a numeric array. Input will read the numbers one at a time, 'stopping' after each is input. Numbers can be separated by 'anything' (so lines of text will be skipped).

Writing a file to the disk

[edit | edit source]

The function for writing a file to disk is easier:

SUB SaveFile (outfile$)
  SHARED filename$
  SHARED lines, maxlines
  SHARED text() AS STRING
  SHARED errorflag
  
  IF outfile$ = "" THEN
    LOCATE 1, 1
    INPUT "Enter filename: "; outfile$
  END IF

  OPEN outfile$ FOR OUTPUT AS 1
  IF errorflag <> 0 THEN
    errorflag = 0
    CLOSE
    PRINT "Couldn't save file - press return to continue."
    INPUT "", a$
    EXIT SUB
  END IF

  ' Write each line to the file
  FOR cline = 1 TO lines
    PRINT #1, text(cline)
  NEXT

  CLOSE 1
  errorflag = 0
  filename$ = outfile$

END SUB

In order to create a new file, you have to open it for OUTPUT, then close it. Example:

OPEN NEWFILE FOR OUTPUT AS #1
CLOSE #1

NOTE: If you accidently open an existing file, all of its contents will be overwritten!