I have read QBasic data files in COBOL many times. The easy solution is when creating random files you need to make them two bytes longer by including X”0D0A”. This adds the end-of-record & return string. This will cause the data records look like they were written with the PRINT statement.
I hope this helps. All records of this type can be opened with EDIT, NOTEPAD, or printed with the TYPE command. Your only problen is if you pack/store numeric data. I always store numeric data in character format.
Here is a definition for the end-of-record string.
EOL$ = CHR$(13) + CHR$(10): ' SET UP END OF LINE CONSTANTS = X"0D0A"
here are comments in the program defining the record layout.
' RECORD FORMAT 2 IS FOR THE DATA RECORDS USING THE FOLLOWING SAMPLE FORMAT:
'
' COL-COL DESCRIPTION FORMAT
'
' 01-05 EMP. NUMBER 5 CHARACTERS REPRESENTING THE EMP. NUMBER
' 06-20 LAST NAME 15 CHARACTERS REPRESENTATION OF LAST NAME
' 21-22 INITIALS 2 CHARACTERS REPRESENTATION OF EMP.s INIT
' 23-24 ACTIVITY CODE 2 CHARACTERS REPRESENTATION OF ACTIVITY
' 25-25 CODE 1 CHARACTERS REPRESENTATION OF CODE
' 26-31 DOLLAR AMOUNT 6 CHARACTERS REPRESENTATION $,$$$.cc
' 32-40 SOCIAL SECURITY # 9 CHARACTERS REPRESENTATION OF SS#
' 41-42 EOL 2 CHARACTERS REPRESENTATION X'0D0A'F
HERE IS THE WRITE A RECORD ROUTINE.
'*************************************************************
' ROUTINE TO PREFORMAT EMPLOYEE RECORD DISK AREA
PREFORMAT.RECORDS:
FOR I% = 1 TO SLOTS%
LSET OUTEMP$ = "-----"
LSET OUTLNAME$ = "LLLLLLLLLLLLLLL"
LSET OUTINIT$ = "II"
LSET OUTACTIVITY$ = "00"
LSET OUTCODE$ = "X"
LSET OUTAMOUNT$ = "000000"
LSET SS$ = "SSSSSSSSS"
LSET F$ = EOL$ :’ this places the x”0D0A” at the end of each record
PUT #2, I%
FOLLOWING IS THE COMPLETE LOAD PROGRAM.
'----------------------------------------------------------------------------
' PROGRAM NAME IS "\QBASIC\RANDLOAD.BAS", IT READS RECORDS, RANDOMIZES TO
' RECORD LOCATIONS/SLOTS USING SPILL FORWARD TECHNIQUE FOR SYNONYMS.
' THE RANDOMIZE TECHNIQUE IS SIMPLE DIVIDE-REMAINDER
' SAMPLE BATCH FILES FOR TESTING ARE 'RANDTEST.BAT' & 'RANDLOAD.BAT'
'----------------------------------------------------------------------------
OPEN "C:\QBASIC\RAND_LOG.LOG" FOR OUTPUT AS #3
GOSUB GET.PASSED.PARAMETERS: ' PARAMETERS PASSED FROM THE RANDLOAD BATCH FILE
PACK.RATE = PACK.FACTOR: PRINT #3, "PACKING RATE % IS "; PACK.RATE: PRINT #3, " "
GOSUB CALC.PACK
SLOTS% = ALLOC.SIZE ' SET UP INITIAL # OF SLOTS
EOL$ = CHR$(13) + CHR$(10): ' SET UP END OF LINE CONSTANTS = X"0D0A"
OPEN OUT.FILE$ FOR RANDOM AS #2 LEN = LONGEST.LEN + 3
' RECORD LAYOUTS *****************************************************
'---------------------------------------------------------------------
' RECORD LAYOUT OF CONTROL RECORD TYPE 2 -----------------------------
FIELD #2, 1 AS CTRL.CODE$, 6 AS ALLOC.SLOTS$, 6 AS ACTUAL.RECS$
FIELD #2, 13 AS FILL2$, 6 AS KEY.SIZE$, 6 AS KEY.LOC$, 2 AS PACKED.OUT$
FIELD #2, 42 AS FILLER$
'---------------------------------------------------------------------
' RECORD 1 FORMAT IS FOR THE CONTROL RECORD WITH THE FOLLOWING FORMAT:
'
' COL-COL DESCRIPTION FORMAT
' 01 CONTROL RECORD CODE 1 CHARACTER "~"
' 02-07 NUMBER OF SLOTS 6 CHARACTERS REPRESENTATION OF # OF SLOTS
' 08-13 NUMBER OF DATA RECORDS 6 CHARACTERS REPRESENTATION OF # OF RECS
' 14-19 KEY SIZE 6 CHARACTERS REPRESENTATION OF KEY START
' 20-25 KEY LOCATION 6 CHARACTERS REPRESENTATION OF KEY SIZE
' 26-27 PACKING FACTOR 2 CHARACTERS REPRESENTATION PACK FACTOR
' 28-42 BLANKS 15 CHARACTERS TO FILL OUT THE RECORD FORMAT
'----------------------------------------------------------------------------
' RECORD LAYOUT OF DETAIL RECORDS ------------------------------------
FIELD #2, 5 AS OUTEMP$, 15 AS OUTLNAME$, 2 AS OUTINIT$, 2 AS OUTACTIVITY$
FIELD #2, 24 AS FILL$, 1 AS OUTCODE$, 6 AS OUTAMOUNT$
FIELD #2, 31 AS FILL$, 9 AS SS$, 2 AS F$
'----------------------------------------------------------------------------
' RECORD FORMAT 2 IS FOR THE DATA RECORDS USING THE FOLLOWING SAMPLE FORMAT:
'
' COL-COL DESCRIPTION FORMAT
'
' 01-05 EMP. NUMBER 5 CHARACTERS REPRESENTING THE EMP. NUMBER
' 06-20 LAST NAME 15 CHARACTERS REPRESENTATION OF LAST NAME
' 21-22 INITIALS 2 CHARACTERS REPRESENTATION OF EMP.s INIT
' 23-24 ACTIVITY CODE 2 CHARACTERS REPRESENTATION OF ACTIVITY
' 25-25 CODE 1 CHARACTERS REPRESENTATION OF CODE
' 26-31 DOLLAR AMOUNT 6 CHARACTERS REPRESENTATION $,$$$.cc
' 32-40 SOCIAL SECURITY # 9 CHARACTERS REPRESENTATION OF SS#
' 41-42 EOL 2 CHARACTERS REPRESENTATION X'0D0A'F
'----------------------------------------------------------------------------
' PRE-FORMAT THE FILE's DATA AREA FOR LOADING
GOSUB PREFORMAT.RECORDS: ' INITALIZE WHOLE RANDOM FILE WITH
' NULL RECORD FORMATS.
OPEN IN.FILE$ FOR INPUT AS #1: ' OPEN INDATA FILE FOR LOADING
'---------------------------------------------------------------------
READ.MORE.RECORDS:
IF EOF(1) THEN GOTO NO.MORE.RECS
LINE INPUT #1, INREC$
IF LEN(INREC$) < KEY.START + KEY.LENGTH - 1 THEN GOTO READ.MORE.RECORDS
PRINT #3, INREC$: ' LIST RECORDS DURING LOAD FOR AUDIT TRAIL
EMPNO$ = MID$(INREC$, 1, 5): ' --
EMPLNAME$ = MID$(INREC$, 6, 15): ' EMPINIT$ = MID$(INREC$, 21, 2): ' \ FORMAT EACH INSERTED RECORD
EMPACTIVITY$ = MID$(INREC$, 23, 2): ' / IN CHARACTER FORMAT
EMPCODE$ = MID$(INREC$, 25, 1): ' /
EMPAMOUNT$ = MID$(INREC$, 26, 6): ' /
EMPSS$ = MID$(INREC$, 31, 9): ' /
GOSUB FIND.A.PLACE
INITRR% = RR%: ' SAVE INITIAL DESIRED FILE LOCATION
NO.EMPTY.REC:
' PRINT OUT RECORD LOAD LOG RECORD
TEST.COUNT = TEST.COUNT + 1
PRINT #3, "TEST SLOT";
PRINT #3, USING "#####"; RR%;
PRINT #3, " AS A PLACE FOR EMPLOYEE="; EMPNO!
GET #2, RR%
IF OUTEMP$ <> "-----" THEN GOSUB SPILL.FORWARD: GOTO NO.EMPTY.REC
PRINT #3, " RECORD FOR"; EMPNO!; " ACTUALLY WRITTEN AT SLOT"; RR%: PRINT #3,
LSET FILLER$ = SPACE$(42): ' FILL OUR DATA RECORDS WITH BLANKS
LSET OUTEMP$ = EMPNO$
LSET OUTLNAME$ = EMPLNAME$
LSET OUTINIT$ = EMPINIT$
LSET OUTACTIVITY$ = EMPACTIVITY$
LSET OUTCODE$ = EMPCODE$
LSET OUTAMOUNT$ = EMPAMOUNT$
LSET SS$ = EMPSS$
LSET F$ = EOL$
PUT #2, RR%
NO.RECS = NO.RECS + 1
GOTO READ.MORE.RECORDS
' ************************************************************
' END OF PROGRAM ROUTINE, WRITE CONTROL RECORD AND SHUT DOWN
NO.MORE.RECS:
FULL: ' THE RANDOM DATA SET AREA IS FULL. DELETE UNUSED RECORDS OR REALLOCATE
LSET FILLER$ = SPACE$(42): ' FILL OUR CONTROL RECORDS WITH BLANKS
'-----------------------------
LSET CTRL.CODE$ = "^"
'-----------------------------
NO.SLOTS$ = LTRIM$(STR$(SLOTS%))
PAD.NO.SLOTS: IF LEN(NO.SLOTS$) < 6 THEN NO.SLOTS$ = "0" + NO.SLOTS$: GOTO PAD.NO.SLOTS
LSET ALLOC.SLOTS$ = NO.SLOTS$: ' LIKE=>"000030"
'-----------------------------
NO.RECS$ = LTRIM$(STR$(NO.RECS))
PAD.NO.RECS: IF LEN(NO.RECS$) < 6 THEN NO.RECS$ = "0" + NO.RECS$: GOTO PAD.NO.RECS
LSET ACTUAL.RECS$ = NO.RECS$: ' LIKE=>"000020"
'-----------------------------
PAD.KEY.SIZE: IF LEN(KEY.LENGTH$) < 6 THEN KEY.LENGTH$ = "0" + KEY.LENGTH$: GOTO PAD.KEY.SIZE
LSET KEY.SIZE$ = KEY.LENGTH$: 'LIKE=>"000005"
'-----------------------------
PAD.KEY.START: IF LEN(KEY.START$) < 6 THEN KEY.START$ = "0" + KEY.START$: GOTO PAD.KEY.START
LSET KEY.LOC$ = KEY.START$: ' LIKE=>"000001"
'-----------------------------
LSET PACKED.OUT$ = PACK.FACTOR$: ' LIKE=>"67"
'-----------------------------
LSET F$ = EOL$
PUT #2, 1' WRITE CONTROL RECORD
LSET OUTEMP$ = CHR$(26) + " ": PUT #2, SLOTS% + 1
PRINT #3, "END OF FILE"
PRINT #3, "AVERAGE NUMBER OF WRITE ATTEMPTS PER RECORD IS =>";
PRINT #3, USING "#.##"; TEST.COUNT / REC.COUNT
CLOSE #1: CLOSE #2: CLOSE 3: SYSTEM: END
'*************************************************************
' ROUTINE TO SPILL FORWARD FOR NEXT FILE SLOT LOCATION
' SPILL OFF THE END IS CORRECTED BY WRAP AROUND.
SPILL.FORWARD:
RR% = RR% + 1: ' NOW TRY NEXT HIGHER SLOT OR WRAP TO RECORD 2
IF RR% > SLOTS% + 1 THEN RR% = 2: ' ON END WRAP AROUND, SKIP CONTROL RECORD 1
IF RR% = INITRR% THEN GOSUB TELL.OPERATOR: GOTO FULL
RETURN
'*************************************************************
' THIS ROUTINE REMOVES BLANK LINES AND DETERMINES MAX/MIN REC SIZE
PREVIEW.FILE.RECORD.SIZE:
OPEN IN.FILE$ FOR INPUT AS #4: ' OPEN INPUT DATA FILE FOR LOADING
SHORTEST.LEN = 1000: LONGEST.LEN = 0: 'PRIME THE LENGTH VALUES
PREVIEW.MORE:
IF EOF(4) THEN GOTO END.OF.PREVIEW
LINE INPUT #4, INREC$
INREC$ = LTRIM$(INREC$)
REC.LEN = LEN(INREC$)
IF REC.LEN = 0 THEN GOTO PREVIEW.MORE
IF REC.LEN > LONGEST.LEN THEN LONGEST.LEN = REC.LEN
IF REC.LEN < SHORTEST.LEN THEN SHORTEST.LEN = REC.LEN
GOTO PREVIEW.MORE
END.OF.PREVIEW:
CLOSE #4
RETURN
'*************************************************************
' ROUTINE TO PREFORMAT EMPLOYEE RECORD DISK AREA
PREFORMAT.RECORDS:
FOR I% = 1 TO SLOTS%
LSET OUTEMP$ = "-----"
LSET OUTLNAME$ = "LLLLLLLLLLLLLLL"
LSET OUTINIT$ = "II"
LSET OUTACTIVITY$ = "00"
LSET OUTCODE$ = "X"
LSET OUTAMOUNT$ = "000000"
LSET SS$ = "SSSSSSSSS"
LSET F$ = EOL$
PUT #2, I%
NEXT I%
RETURN
'*************************************************************
' RANDOMIZE USING SIMPLE DIVIDE/REMAINDER TECHNIQUE
FIND.A.PLACE:
' EMPNO! = VAL(EMPNO$): ' GET NUMERIC VALUE OF EMPLOYEE #
EMPNO! = VAL(MID$(INREC$, KEY.START, KEY.LENGTH)): ' GET NUMERIC VALUE OF EMPLOYEE #
RR% = EMPNO! - INT(INT(EMPNO! / SLOTS%) * SLOTS%) + 1
IF RR% = 1 THEN RR% = 2 ' EVEN THE INITIAL RECORD LOCATION
' MUST NOT BE RECORD LOCATION 1
RETURN
'*************************************************************
' CALCULATE INITIAL INPUT RECORD's LOAD AREA
' PACKING FACTOR MULTIPLIER IS PACK.MULT = 1 +(1-PERCENT)/PERCENT
CALC.PACK:
PERCENT = PACK.RATE / 100
PACK.MULT = 1 + (1 - PERCENT) / PERCENT
OPEN IN.FILE$ FOR INPUT AS #1
COUNT.LOOP:
IF EOF(1) GOTO GOT.COUNT
LINE INPUT #1, INREC$
REC.COUNT = REC.COUNT + 1
GOTO COUNT.LOOP
GOT.COUNT:
CLOSE #1
ALLOC.SIZE = INT(REC.COUNT * PACK.MULT) + 1
' PRINT ALLOC.SIZE, REC.COUNT, PACK.MULT
RETURN
'************************************************
TELL.OPERATOR:
PRINT #3, "LOOPED BACK TO START, NO SLOTS LEFT, FILE CLOSED"
CLS
LOCATE 10, 1
PRINT "FILE '"; OUT.FILE$; "' IS FULL, LAST RECORD IN PROCESS WAS:"
PRINT INREC$; CHR$(7);
PRINT
PRINT "PRESS ANY KEY TO CONTINUE"
KEY.LOOP: KEY.IN$ = INKEY$: IF KEY.IN$ = "" THEN GOTO KEY.LOOP
RETURN
'*************************************************************
' THIS ROUTINE WORKS IN CONJUNCTION WITH 'RANDLOAD.BAT' SCRIPT
' OF WHICH A COPY FOLLOWS AS COMMENTS AND DOCUMENTATION.
'*************************************************************
GET.PASSED.PARAMETERS:
IN.FILE$ = ENVIRON$("RANDIN"

OUT.FILE$ = ENVIRON$("RANDOUT"
KEY.START$ = ENVIRON$("KEYSTART"

KEY.START = VAL(ENVIRON$("KEYSTART"

)
KEY.LENGTH$ = ENVIRON$("KEYLENGTH"

KEY.LENGTH = VAL(ENVIRON$("KEYLENGTH"

)
PACK.FACTOR$ = ENVIRON$("PACK"

PACK.FACTOR = VAL(ENVIRON$("PACK"

)
PRINT #3, "INPUT FILE IS =>"; IN.FILE$
PRINT #3, "OUTPUT FILE IS =>"; OUT.FILE$
PRINT #3, "KEY START POSITION IS =>"; KEY.START$
PRINT #3, "KEY LENGTH IS =>"; KEY.LENGTH$
PRINT #3, "THE PACKING FACTOR IS =>"; PACK.FACTOR$
' LOOP THROUGH THE INPUT FILE, FIND LARGEST, SMALLEST AND REMOVE BLANK LINES
GOSUB PREVIEW.FILE.RECORD.SIZE
PRINT #3, "THE SHORTEST RECORD IS =>"; SHORTEST.LEN
PRINT #3, "THE LONGEST RECORD IS =>"; LONGEST.LEN
PRINT #3,
RETURN
' ***** SAMPLE 'RANDLOAD.BAT SCRIPT *************
' REM @ECHO OFF
' REM SAMPLE TEST BATCH CODING :
' REM
' REM RANDLOAD filein fileout keyloc keylen pack%
' REM RANDLOAD EMPIN.TXT RANOUT.DTA 1 5 80
' REM
' ECHO END OF RANDOM LOAD OF %1 INTO %2 USING KEY START AT %3, LENGTH %4 PACK %5
' SET RANDIN=%1
' SET RANDOUT=%2
' SET KEYSTART=%3
' SET KEYLENGTH=%4
' SET PACK=%5
' C:\QBASIC\QBASIC /RUN RANDLOAD.BAS
' ECHO END OF RANDOM LOAD OF %RANDIN% INTO %RANDOUT% USING KEY START AT %KEYSTART%, LENGTH %KEYLENGTH% PACK %PACK%