7.6 Truncating a File
If you open an existing file (using fileio.open) for output and write data to that file, it overwrites the existing data from the start of the file. However, if the new data you write to the file is shorter than the data originally appearing in the file, the excess data from the original file, beyond the end of the new data you've written, will still appear at the end of the new data. Sometimes this might be desirable, but most of the time you'll want to delete the old data after writing the new data.
One way to delete the old data is to use the fileio.openNew function to open the file. The fileio.openNew function automatically deletes any existing file so only the data you write to the file will be present in the file. However, there may be times when you may want to read the old data first, rewind the file, and then overwrite the data. In this situation, you'll need a function that will truncate the old data at the end of the file after you've written the new data. The fileio.truncate function accomplishes this task. This function uses the following calling syntax:
fileio.truncate( fileHandle );Note that this function does not close the file. You still have to call fileio.close to commit the data to the disk.
The following sample program demonstrates the use of the fileio.truncate function:
program TruncateDemo; #include( "stdlib.hhf" ) static fileHandle:dword; u:uns32; begin TruncateDemo; fileio.openNew( "myfile.txt" ); mov( eax, fileHandle ); for( mov( 0, ecx ); ecx < 20; inc( ecx )) do fileio.put( fileHandle, (type uns32 ecx), nl ); endfor; // Okay, let's rewind to the beginning of the file and // rewrite the first ten lines and then truncate the // file at that point. fileio.rewind( fileHandle ); for( mov( 0, ecx ); ecx < 10; inc( ecx )) do fileio.put( fileHandle, (type uns32 ecx), nl ); endfor; fileio.truncate( fileHandle ); // Rewind and display the file contents to ensure that // the file truncation has worked. fileio.rewind( fileHandle ); while( !fileio.eof( fileHandle )) do // Read and display the next item from the file: fileio.get( fileHandle, u ); stdout.put( "u=", u, nl ); fileio.readLn( fileHandle ); endwhile; fileio.close( fileHandle ); end TruncateDemo; Program 7.7 Using fileio.truncate to Eliminate Old Data From a File7.7 File Utility Routines
The following subsections describe fileio functions that manipulate files or return meta-information about files (e.g., the file size and attributes).
program CopyDemo; #include( "stdlib.hhf" ) begin CopyDemo; // Make a copy of myfile.txt to itself to demonstrate // a true "failsIfExists" parameter. if( !fileio.copy( "myfile.txt", "myfile.txt", true )) then stdout.put( "Did not copy `myfile.txt' over itself" nl ); else stdout.put( "Whoa! The failsIfExists parameter didn't work." nl ); endif; // Okay, make a copy of the file to a different file, to verify // that this works properly: if( fileio.copy( "myfile.txt", "copyOfMyFile.txt", false )) then stdout.put( "Successfully copied the file" nl ); else stdout.put( "Failed to copy the file (maybe it doesn't exist?)" nl ); endif; end CopyDemo; program FileMoveDemo; #include( "stdlib.hhf" ) begin FileMoveDemo; // Rename the "myfile.txt" file to the name "renamed.txt". if( !fileio.move( "myfile.txt", "renamed.txt" )) then stdout.put ( "Could not rename `myfile.txt' (maybe it doesn't exist?)" nl ); else stdout.put( "Successfully renamed the file" nl ); endif; end FileMoveDemo;7.7.1 Computing the File Size
Another useful function to have is one that computes the size of an existing file on the disk. The fileio.size function provides this capability. The calling sequences for this function are
fileio.size( filenameString ); fileio.size( fileHandle );The first form above expects you to pass the filename as a string parameter. The second form expects a handle to a file you've opened with fileio.open or fileio.openNew. These two calls return the size of the file in EAX. If an error occurs, these functions return -1 ($FFFF_FFFF) in EAX. Note that the files must be less than four gigabytes in length when using this function (if you need to check the size of larger files, you will have to call the appropriate OS function rather than these functions; however, since files larger than four gigabytes are rather rare, you probably won't have to worry about this problem).
One interesting use for this function is to determine the number of records in a fixed-length-record random access file. By getting the size of the file and dividing by the size of a record, you can determine the number of records in the file.
Another use for this function is to allow you to determine the size of a (smaller) file, allocate sufficient storage to hold the entire file in memory (by using malloc), and then read the entire file into memory using the fileio.read function. This is generally the fastest way to read data from a file into memory.
Program 7.8 demonstrates the use of the two forms of the fileio.size function by displaying the size of the "myfile.txt" file created by other sample programs in this chapter.
program FileSizeDemo; #include( "stdlib.hhf" ) static handle:dword; begin FileSizeDemo; // Display the size of the "FileSizeDemo.hla" file: fileio.size( "FileSizeDemo.hla" ); if( eax <> -1 ) then stdout.put( "Size of file: ", (type uns32 eax), nl ); else stdout.put( "Error calculating file size" nl ); endif; // Same thing, using the file handle as a parameter: fileio.open( "FileSizeDemo.hla", fileio.r ); mov( eax, handle ); fileio.size( handle ); if( eax <> -1 ) then stdout.put( "Size of file(2): ", (type uns32 eax), nl ); else stdout.put( "Error calculating file size" nl ); endif; fileio.close( handle ); end FileSizeDemo; Program 7.8 Sample Program That Demonstrates the fileio.size Function7.7.2 Deleting Files
Another useful file utility function is the fileio.delete function. As its name suggests, this function deletes a file that you specify as the function's parameter. The calling sequence for this function is
fileio.delete( filenameToDelete );The single parameter is a string containing the pathname of the file you wish to delete. This function returns true/false in the EAX register to denote success/failure.
Program 7.9 provides an example of the use of the fileio.delete function.
program DeleteFileDemo; #include( "stdlib.hhf" ) static handle:dword; begin DeleteFileDemo; // Delete the "myfile.txt" file: fileio.delete( "xyz" ); if( eax ) then stdout.put( "Deleted the file", nl ); else stdout.put( "Error deleting the file" nl ); endif; end DeleteFileDemo; Program 7.9 Example Usage of the fileio.delete Procedure7.8 Directory Operations
In addition to manipulating files, you can also manipulate directories with some of the fileio functions. The HLA Standard Library includes several functions that let you create and use subdirectories. These functions are fileio.cd (change directory), fileio.gwd (get working directory), and fileio.mkdir (make directory). Their calling sequences are
fileio.cd( pathnameString ); fileio.gwd( stringToHoldPathname ); fileio.mkdir( newDirectoryName );The fileio.cd and fileio.mkdir functions return success or failure (true or false, respectively) in the EAX register. For the fileio.gwd function, the string parameter is a destination string where the system will store the pathname to the current directory. You must allocate sufficient storage for the string prior to passing the string to this function (260 characters1 is a good default amount if you're unsure how long the pathname could be). If the actual pathname is too long to fit in the destination string you supply as a parameter, the fileio.gwd function will raise the ex.StringOverflow exception.
The fileio.cd function sets the current working directory to the pathname you specify. After calling this function, the OS will assume that all future "unadorned" file references (those without any "\" or "/""/" characters in the pathname) will default to the directory you specify as the fileio.cd parameter. Proper use of this function can help make your program much more convenient to use by your program's users since they won't have to enter full pathnames for every file they manipulate.
The fileio.gwd function lets you query the system to determine the current working directory. After a call to fileio.cd, the string that fileio.gwd returns should be the same as fileio.cd's parameter. Typically, you would use this function to keep track of the default directory when your program first starts running. You program will exhibit good manners by switching back to this default directory when your program terminates.
The fileio.mkdir function lets your program create a new subdirectory. If your program creates data files and stores them in a default directory somewhere, it's good etiquette to let the user specify the subdirectory where your program should put these files. If you do this, you should give your users the option to create a new directory (in case they want the data placed in a brand-new directory). You can use fileio.mkdir for this purpose.
7.9 Putting It All Together
This chapter began with a discussion of the basic file operations. That section was rather short because you've already learned most of what you need to know about file I/O when learning the stdout and stdin functions. So the introductory material concentrated on a file general file concepts (like the differences between sequential and random access files and the differences between binary and text files). After teaching you the few extra routines you need in order to open and close files, the remainder of this chapter simply concentrated on providing a few examples (like ISAM) of file access and a discussion of the fileio routines available in the HLA Standard Library.
While this chapter demonstrates the mechanics of file I/O, how you efficiently use files is well beyond the scope of this chapter. In future volumes you will see how to search for data in files, sort data in files, and even create databases. So keep on reading if you're interested in more information about file operations.
1This is the default MAX_PATH value in Windows. This is probably sufficient for most Linux applications, too.
|