Truncating a BINARY file under QB4.5/VBDOS?

If you have questions about any aspect of QBasic programming, or would like to help fellow programmers solve their problems, check out this board!

Moderators: Pete, Mods

Post Reply
Harry Potter
Veteran
Posts: 111
Joined: Sat Feb 21, 2009 8:19 am
Location: New York, U.S.

Truncating a BINARY file under QB4.5/VBDOS?

Post by Harry Potter »

Let's say I'm writing a BINARY file under QB4.5/VBDOS and need to end it earlier than the original length. When I close the file, how do I truncate it at the last write pos.?
User avatar
burger2227
Veteran
Posts: 2466
Joined: Mon Aug 21, 2006 12:40 am
Location: Pittsburgh, PA

Post by burger2227 »

TRUNCATION of RANDOM files from MS site:

You can invoke MS-DOS service functions using the CALL INTERRUPT statement in Basic.

You can set the size of any file to any arbitrary value by executing MS-DOS Interrupt 21h
with service 40h using CX = 00h. The usual technique is to call service 42h to set the file
pointer location and then immediately call service 40h with CX = 00h to update the new file size.

The program below is written so that the Truncate% FUNCTION is generic as possible and works
with any file. ProcessFile() sets up the file-specific information, which in turn calls the
Truncate% FUNCTION. Truncate% generates the specific interrupt calls to truncate the file at
the specified record. The two SUB programs PrintFile() and CreateFile() are only needed as an
example.


Program Example
To try this example in VBDOS.EXE:
From the File menu, choose New Project.
Copy the code example to the Code window.
Press F5 to run the program.
To run this program in the VBDOS.EXE environment, you must invoke the VBDOS.EXE environment
with the /L switch to load the default Quick library. For example:

VBDOS.EXE /L

You must run QB or QBX with the /L option to load the QB.QLB or QBX.QLB Quick library which
contains the INTERRUPT routine used in this program. You must LINK with QB.LIB or QBX.LIB when
making an .EXE program which uses the CALL INTERRUPT statement.
_____________________________________________________________________________

CONST NumRec = 10, LastRec% = '? Enter last record to keep!
TYPE TheType
i AS INTEGER
END TYPE
DIM SHARED TheDim AS TheType
' Use the following include file for Visual Basic for MS-DOS:
REM $INCLUDE: 'VBDOS.BI'
' Use the following include file for QuickBasic for MS-DOS:
'$INCLUDE: 'QB.BI'
' Use the following include file for Basic PDS for MS-DOS:
'$INCLUDE: 'QBX.BI'
CALL CreateFile 'creates a Demo test file
CALL PrintFile 'displays created test file
CALL ProcessFile(7) 'process and truncate file
CALL PrintFile 'display truncated file

'################### File specific SUB #############################
SUB ProcessFile (LastRec%)
' Get the information about "TEST.DAT" and also the information
' about the location of the LASTREC% where the file will be truncated.
OPEN "test.dat" FOR RANDOM AS #1 LEN = LEN(TheDim)
FilePointer% = LastRec% * LEN(TheDim) '<--User's desired Last Record
IF FilePointer% <> Truncate%(FILEATTR(1, 2), FilePointer%) THEN
PRINT "error..."
END IF
CLOSE
END SUB

'################## Generic INT file truncator ####################
FUNCTION Truncate% (handle%, FilePointer%)
' Generic function that will truncate any file at specified offset.
'
' Receives:
' 1. a MS-DOS file handle;
' 2. a file pointer offset in bytes, pointing where to truncate
' Returns:
' 1. If successful, position of file pointer; or
' 2. If error, flags register
'
DIM Regs AS RegType
Regs.ax = &H4200 ' INT 21h, service 42h
Regs.bx = handle% ' MS-DOS Handle
Regs.dx = FilePointer% ' Offset in bytes from start.
CALL Interrupt(&H21, Regs, Regs)
IF Regs.ax <> FilePointer% THEN ' AX returns pointer position.
Truncate% = Regs.flags: EXIT FUNCTION ' If error, return flag.
END IF
Regs.ax = &H4000 ' INT 21h, service 40h
Regs.bx = handle% ' MS-DOS handle
Regs.cx = &H0
CALL Interrupt(&H21, Regs, Regs)
IF Regs.ax <> 0 THEN ' Must be zero bytes written.
Truncate% = Regs.flags: EXIT FUNCTION ' If error, return flag.
END IF
Truncate% = FilePointer% ' Return offset location.
END FUNCTION

'############ Create Sample File using RANDOM Access ################
SUB CreateFile
KILL "test.dat"
OPEN "test.dat" FOR RANDOM AS #1 LEN = LEN(TheDim)
FOR j = 1 TO NumRec
TheDim.i = j
PUT #1, j, TheDim
NEXT j
CLOSE #1
END SUB

'########### Print contents of TEST.DAT ##################
SUB PrintFile
OPEN "test.dat" FOR RANDOM AS #1 LEN = LEN(TheDim)
Max = LOF(1) / LEN(TheDim)
FOR j = 1 TO Max
GET #1, j, TheDim
PRINT TheDim.i
NEXT j
CLOSE
END SUB

I added the two EXIT FUNCTION parts to the Function! Flag should return 1. So add something to abort the process when 1 is returned. Use the last SEEK position to find your last record position. I don't know how well this would work in BINARY files!

I don't see this as a GREAT alternative to just swapping files! I don't like KILL without a backup!

Why are you truncating a BINARY file? Let me know if it works.

Ted
Please acknowledge and thank members who answer your questions!
QB64 is a FREE QBasic compiler for WIN, MAC(OSX) and LINUX : https://www.qb64.org/forum/index.php
Get my Q-Basics demonstrator: https://www.dropbox.com/s/fdmgp91d6h8ps ... s.zip?dl=0
Harry Potter
Veteran
Posts: 111
Joined: Sat Feb 21, 2009 8:19 am
Location: New York, U.S.

Post by Harry Potter »

Thank you. I will look at it later.
Post Reply