SUB selectFileToBuffer(fileNumber%, bufferSize&) SHARED bufferedFileNumber%, bufferedFileBuffer$, bufferedFileBufferOffset%
IF bufferedFileBufferOffset% THEN flushBuffer
bufferedFileNumber% = fileNumber% bufferedFileBuffer$ = "" bufferedFileBuffer$ = SPACE$(bufferSize&) bufferedFileBufferOffset% = 0 END SUB
SUB writeBufferedChar(character$) SHARED bufferedFileNumber%, bufferedFileBuffer$, bufferedFileBufferOffset%
bufferedFileBufferOffset% = bufferedFileBufferOffset% + 1 MID$(bufferedFileBuffer$, bufferedFileBufferOffset%, 1) = character$ IF bufferedFileBufferOffset% = LEN(bufferedFileBuffer$) THEN PUT #bufferedFileNumber%, , bufferedFileBuffer$ bufferedFileOffset% = 0 END IF END SUB
SUB writeBufferedByte(asciiValue%) writeBufferedChar CHR$(asciiValue%) END SUB
SUB writeBufferedString(stringToWrite$) SHARED bufferedFileNumber%, bufferedFileBuffer$, bufferedFileBufferOffset%
a$ = stringToWrite$ ' Local copy bytesLeft% = LEN(a$) DO WHILE bytesLeft% bytesLeftInBuffer% = LEN(bufferedFileBuffer$) - bufferedFileBufferOffset% IF bytesLeftInBuffer% > bytesLeft THEN EXIT DO
SUB flushBuffer() SHARED bufferedFileNumber%, bufferedFileBuffer$, bufferedFileBufferOffset%
IF bufferedFileBufferOffset% THEN usedBuffer$ = LEFT$(bufferedFileBuffer$, bufferedFileBufferOffset%) PUT #bufferedFileNumber%, , usedBuffer$ bufferedFileBufferOffset% = 0 END IF END SUB
To start using these SUBs, call SUB selectFileToBuffer and pass it a file number opened by OPEN in BINARY mode, as well as a buffer size (4096 or 8192 should be about optimal -- smaller buffers cause degraded performance, but QB has trouble with strings larger than 8 kilobytes (it can do them, but the string space gets all fragmented and messy)).
Then, to output bytes or strings, call the appropriate output function (the routines remember the file number automatically). When you are done, call SUB flushBuffer before closing your file, otherwise some data will not be written to file and will be lost.
You can switch from your own output to this buffered output at any time (provided the file was opened FOR BINARY), and you can switch back to your own output code at any time by calling SUB flushBuffer, however doing so very often would reduce the effectiveness of the buffer and degrade performance. When switching back from your routines to the buffered routines after the buffered routines have already been in use, you do not need to call SUB selectFileToBuffer again, as all the settings are remembered and the buffer is in a proper state from SUB flushBuffer. It should also be safe to switch the buffer from one file to another (it automatically flushes the buffer), but the same performance issue applies.