Exceeding+the+limit+of+8+open+files

//by Richard Russell, October 2015//

Normally only a maximum of eight files may be open simultaneously in //BBC BASIC for Windows//; an attempt to open a ninth file will result in the **Too many open files** error (ERR = 192). It is possible to work around this limitation by opening-and-closing the file for each transaction (so that only one file is open at a time), for example to write a record to a file one might do: code format="bb4w" file% = OPENUP(file$) PTR#file% = EXT#file% PRINT #file$, record$ CLOSE #file% code However this approach has a number of shortcomings: it's messy, it's (relatively) slow - especially if the file is on a network share - and since the file is constantly being opened and closed another process could in principle modify it whilst it is being written.

Fortunately there is an alternative approach which allows an arbitrarily large number of files to be open simultaneously. It involves using replacements for the usual OPENIN, OPENOUT and OPENUP functions. Here is a demonstration program which illustrates how it is possible to have (in this case) 12 files open at the same time: code format="bb4w" NoOfFiles% = 12 DIM Chan%(NoOfFiles%)

REM Create files: FOR file% = 1 TO NoOfFiles% Chan%(file%) = FNopenout(@tmp$ + "file" + STR$(file%)) NEXT file%

REM Write to files: FOR file% = 1 TO NoOfFiles% PRINT #Chan%(file%), "This is file " + STR$(file%) NEXT file%

REM Close files: FOR file% = 1 TO NoOfFiles% CLOSE #Chan%(file%) NEXT file%

REM Open files for update: FOR file% = 1 TO NoOfFiles% Chan%(file%) = FNopenup(@tmp$ + "file" + STR$(file%)) NEXT file%

REM Append to files: FOR file% = 1 TO NoOfFiles% PTR#Chan%(file%) = EXT#Chan%(file%) PRINT #Chan%(file%), "Appended to file " + STR$(file%) NEXT file%

REM Close files: FOR file% = 1 TO NoOfFiles% CLOSE #Chan%(file%) NEXT file%

REM Open files for input: FOR file% = 1 TO NoOfFiles% Chan%(file%) = FNopenin(@tmp$ + "file" + STR$(file%)) NEXT file%

REM Read files and display contents: FOR file% = 1 TO NoOfFiles% INPUT #Chan%(file%), first$, second$ PRINT first$; " " second$ NEXT file%

REM Close files: FOR file% = 1 TO NoOfFiles% CLOSE #Chan%(file%) NEXT file%

REM Delete files: FOR file% = 1 TO NoOfFiles% OSCLI "DELETE " + @tmp$ + "file" + STR$(file%) NEXT file%

END code Note that if this technique is used the CLOSE #0 statement (which normally closes all open files) will close only the first eight.

Here are the replacement functions which allow this magic to happen: code format="bb4w" DEF FNopenin(F$) LOCAL E%,F%,H% SWAP H%,!500 : SWAP E%,!532 F% = OPENIN(F$) IF H% SWAP H%,!500 : SWAP E%,!532 : IF H% F% = H%     = F%

DEF FNopenout(F$) LOCAL E%,F%,H% SWAP H%,!500 : SWAP E%,!532 F% = OPENOUT(F$) IF H% SWAP H%,!500 : SWAP E%,!532 : IF H% F% = H%     = F%

DEF FNopenup(F$) LOCAL E%,F%,H% SWAP H%,!500 : SWAP E%,!532 F% = OPENUP(F$) IF H% SWAP H%,!500 : SWAP E%,!532 : IF H% F% = H%     = F% code Please note that only the first eight files will be buffered by BASIC, so files in excess of that number may be accessed a little more slowly.

Please also be aware that the value returned by these replacement functions, for files in excess of the initial eight, is the native Windows file handle. For this to work the Windows file handle must exceed 16, otherwise BB4W will mistake it for a BASIC file channel number. This is normally reliable but there is **nothing in the Microsoft API documentation which states that a file handle will always be greater than 16**.