8.4 Random Access Files


8.4 Random Access Files

The problem with sequential files is that they are, well, sequential. They are great for dumping and retrieving large blocks of data all at once, but they are not suitable for applications that need to read, write, and rewrite the same data in a file multiple times. In those situations random access files provide the only reasonable alternative.

Windows and Linux don't differentiate sequential and random access files anymore than the CPU differentiates byte and character values in memory; it's up to your application to treat the files as sequential or random access. As such, you use many of the same functions to manipulate random access files as you use to manipulate sequential access files; you just use them differently is all.

You still open files with fileio.open and fileio.openNew. Random access files are generally opened for reading or reading and writing. You rarely open a random access file as write-only because a program typically needs to read data if it's jumping around in the file.

You still close the files with fileio.close.

You can read and write the files with fileio.get and fileio.put, although you would not normally use these functions for random access file I/O because each record you read or write has to be exactly the same length and these functions aren't particularly suited for fixed length record I/O. Most of the time you will use one of the following functions to read and write fixed length data:

 fileio.write( fileHandle, buffer, count ); fileio.read( fileHandle, buffer, count ); 

The fileHandle parameter is the usual file handle value (a dword variable). The count parameter is an uns32 object that specifies how many bytes to read or write. The buffer parameter must be an object with at least count bytes. This parameter supplies the address of the first byte in memory where the I/O transfer will take place. These functions return the number of bytes read or written in the EAX register. For fileio.read, if the return value in EAX does not equal count's value, then you've reached the end of the file. For fileio.write, if EAX does not equal count then the disk is full.

Here is a typical call to the fileio.read function that will read a record from a file:

      fileio.read( myHandle, myRecord, @size( myRecord ) ); 

If the return value in EAX does not equal @size( myRecord ) and it does not equal zero (indicating end of file), then there is something seriously wrong with the file because the file should contain an integral number of records.

Writing data to a file with fileio.write uses a similar syntax to fileio.read.

You can use fileio.read and fileio.write to read and write data from/to a sequential file, just as you can use routines like fileio.get and fileio.put to read/write data from/to a random access file. You'd typically use these routines to read and write data from/to a binary sequential file.

The functions we've discussed to this point don't let you randomly access records in a file. If you call fileio.read several times in a row, the program will read those records sequentially from the text file. To do true random access I/O we need the ability to jump around in the file. Fortunately, the HLA Standard Library's file module provides several functions you can use to accomplish this.

The fileio.position function returns the current offset into the file in the EAX register. If you call this function immediately before reading or writing a record to a file, then this function will tell you the exact position of that record. You can use this value to quickly locate that record for a future access. The calling sequence for this function is

      fileio.position( fileHandle ); // Returns current file position in EAX. 

The fileio.seek function repositions the file pointer to the offset you specify as a parameter. The following is the calling sequence for this function:

      fileio.seek( fileHandle, offset ); // Repositions file to specified offset. 

The function call above will reposition the file pointer to the byte offset specified by the offset parameter. If you feed this function the value returned by fileio.position, then the next read or write operation will access the record written (or read) immediately after the fileio.position call.

You can pass any arbitrary offset value as a parameter to the fileio.seek routine; this value does not have to be one that the fileio.position function returns. For random access file I/O you would normally compute this offset file by specifying the index of the record you wish to access multiplied by the size of the record. For example, the following code computes the byte offset of record index in the file, repositions the file pointer to that record, and then reads the record:

      intmul( @size( myRecord ), index, ebx );      fileio.seek( fileHandle, ebx );      fileio.read( fileHandle, (type byte myRecord), @size( myRecord ) ); 

You can use essentially this same code sequence to select a specific record in the file for writing.

Note that it is not an error to seek beyond the current end of file and then write data. If you do this, the OS will automatically fill in the intervening records with uninitialized data. Generally, this isn't a great way to create files, but it is perfectly legal. On the other hand, be aware that if you do this by accident, you may wind up with garbage in the file and no error to indicate that this has happened.

The fileio module provides another routine for repositioning the file pointer: fileio.rSeek. This function's calling sequence is very similar to fileio.seek; it is

      fileio.rSeek( fileHandle, offset ); 

The difference between this function and the regular fileio.seek function is that this function repositions the file pointer offset bytes from the end of the file (rather than offset bytes from the start of the file). The "r" in "rSeek" stands for "reverse" seek.

Repositioning the file pointer, especially if you reposition it a fair distance from its current location, can be a time-consuming process. If you reposition the file pointer and then attempt to read a record from the file, the system may need to reposition a disk arm (a very slow process) and wait for the data to rotate underneath the disk read/write head. This is why random access I/O is much less efficient than sequential I/O.

The program in Listing 8-6 demonstrates random access I/O by writing and reading a file of records.

Listing 8-6: Random Access File I/O Example.

start example
 program RandomAccessDemo; #include( "stdlib.hhf" ) type    fileRec:       record          x:int16;          y:int16;          magnitude:uns8;       endrecord; const // Some arbitrary data we can use to initialize the file: fileData:=    [       fileRec:[ 2000, 1, 1 ],       fileRec:[ 1000, 10, 2 ],       fileRec:[ 750, 100, 3 ],       fileRec:[ 500, 500, 4 ],       fileRec:[ 100, 1000, 5 ],       fileRec:[ 62, 2000, 6 ],       fileRec:[ 32, 2500, 7 ],       fileRec:[ 10, 3000, 8 ]    ]; static    fileHandle: dword;    RecordFromFile: fileRec;    InitialFileData: fileRec[ 8 ] := fileData; begin RandomAccessDemo;    fileio.openNew( "fileRec.bin" );    mov( eax, fileHandle ); // Okay, write the initial data to the file in a sequential fashion:    for( mov( 0, ebx ); ebx < 8; inc( ebx )) do       intmul( @size( fileRec ), ebx, ecx ); // Compute index into fileData       fileio.write       (          fileHandle,          (type byte InitialFileData[ecx]),          @size( fileRec )       );    endfor;    // Okay, now let's demonstrate a random access of this file    // by reading the records from the file backward.    stdout.put( "Reading the records, backwards:" nl );    for( mov( 7, ebx ); (type int32 ebx) >= 0; dec( ebx )) do       intmul( @size( fileRec ), ebx, ecx ); // Compute file offset       fileio.seek( fileHandle, ecx );       fileio.read       (          fileHandle,          (type byte RecordFromFile),          @size( fileRec )       );       if( eax = @size( fileRec )) then       stdout.put       (           "Read record #",          (type uns32 ebx),          ", values:" nl          " x: ", RecordFromFile.x, nl          " y: ", RecordFromFile.y, nl          " magnitude: ", RecordFromFile.magnitude, nl nl       );    else       stdout.put( "Error reading record number ", (type uns32 ebx), nl );    endif; endfor; fileio.close( fileHandle ); end RandomAccessDemo; 
end example




The Art of Assembly Language
The Art of Assembly Language
ISBN: 1593272073
EAN: 2147483647
Year: 2005
Pages: 246
Authors: Randall Hyde

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net