Wiki Home

Low Level File Functions


Namespace: Wiki
A.K.A. the LLFF

A series of native Visual Foxpro functions which allow byte-level access to disk files. Functions include:
This file access is handle-based, and can be buffered or unbuffered at the developer's discretion.

These functions also allow access to serial communications.

Some of the tasks which used to require use of these functions can now be done using FILETOSTR(), STRTOFILE(), and ALINES().
When parsing a long file and wanting to report progress to the console, first issue:
lnFileLength = FSEEK([file handle (Numeric)], 0, 2) && Moves pointer to end of file and incidentally returns file length.
FSEEK([file handle (Numeric)], 0, 0) && Resets pointer to the beginning of the file.

Then, as you progress through processing the file, you can determine your current file position using:
lnCurPos = FSEEK([file handle (Numeric)], 0, 1) && Does not move pointer.
and report progress as appropriate.
GOTCHA with FCREATE() and FOPEN(): Both of these functions take a filename parameter optionally followed by another parameter that is the type of access. The accesses are different. For FOPEN(), these are how the file is to be opened and appropriate constants are defined in foxpro.h. For FCREATE(), these are file attributes (as in DOS's attrib). There are NOT any constants defined for these in foxpro.h. In particular:

fh = FCREATE(filename,F_WRITEONLY)

is a gotcha way of creating a READ-ONLY file.
The Low Level File Constants (from foxpro.h) are:
#DEFINE F_READONLY 0
#DEFINE F_WRITEONLY 1
#DEFINE F_READWRITE 2
#DEFINE F_READONLY_UNBUFF 10
#DEFINE F_WRITEONLY_UNBUFF 11
#DEFINE F_READWRITE_UNBUFF 12
FGETS() has an optional second parameter specifying a length limit. It isn't documented in my docs, but this is limited to a maximum of 8192. Feeling silly?
bytesread = FGETS(fh,0) && zero byte read is legal!

The 8,192 limit was imposed in VFP6 SP3 - see:
http://support.microsoft.com/default.aspx?scid=kb;en-us;221747#kb2
* Low level file IO error descriptions, returned by FERROR()
DIME aErrDsc( 31 )
aErrDsc = "Un-documented"
aErrDsc( 2 ) = "File not found"
aErrDsc( 4 ) = "Too many files open (out of handles)"
aErrDsc( 5 ) = "Access denied"
aErrDsc( 6 ) = "Invalid file handle given"
aErrDsc( 8 ) = "Out of memory"
aErrDsc( 25 ) = "Seek error (can't seek before the start of a file)"
aErrDsc( 29 ) = "Disk full"
aErrDsc( 31 ) = "Error opening file or general failure (EOF encountered)"

The Array lets you do this:
lnError = fHrror( lnHandle )
? "Error", lnError, aErrDsc( lnError )

Besides being used for reading flat files and converting to DBF they are cool to edit a file, (i.e to read in a record and modify then write the record out to another file).

In the old FoxPro 2.x days these LLFF were sometimes used to manipulate a byte or two in the DBF header to render the DBF format illegal so it could not be used outside of the program. It was a sort of a poor-man's data security system (not very secure but good enough for the casual user).
One easy sample using LLFF to verify user is not trying to open a second instance of a Fox application on his computer:
lnHandle = fcreate(sys(2023) + 'MyFlagFile.TMP')
if lnHandle < 0
   MessageBox('Already running on this computer!',48,'MyApplication')
   Return .F.
endif

-- Laurent Dujat
Be prepared to do a lot of CLOSE ALL commands while trying to work with these functions. The file handles created are not automatically released when the memvar holding the handle goes out of scope. If this happens CLOSE ALL is the only way to terminate the handle connections.

For example:
fh1 = fopen( "C:\NETLOG.TXT", 0 )
? fh1
fh1 = .null. && simulate handle going out of scope
* "rerun" the code
fh1 = fopen( "C:\NETLOG.TXT", 0 )
? fh1 && -1 failed because it's already open
close all

FWIW, I only use the LLFF when they are the only way to do the task, like byte level file read/write. FileToStr() or code like:

create cursor theFile ( cLine c(254) )
append from c:\netlog.txt type sdf
scan
   * do something interesting with each line
endscan

is much easier to use. -- df
The above about there being no way to handle the file handle variable going out of scope isn't QUITE correct. list/display status will display "User-opened files:" with a line for each giving the filename, handle number, position in the file, whether it's open for reading, and whether it's open for writing. It certainly would be better keep track of the files than to have to parse this though.

Gene - this must be a recent change, I don't remember the file handle being displayed before. Your suggestion works for both VFP5 and VFP6. This is better than having to CLOSE ALL. I still think the other alternatives are better than the LLFF. -- ?df
Actually, "list status" has displayed the file handle since at least Fox 2.5 and maybe earlier. I've had my llCloseAll() function for at least that long. FWIW, I now use a class that wraps all of the LLFF. Besides storing the file handle to a property (which is kind of handy) it closes the LL file when it goes out of scope. Very handy when working with low-level files. Russ Swall
A trick I use to make sure all low-level files are closed:
FOR lnCtr = 1 TO 256
   FCLOSE(lnCtr)
ENDFOR

The 256 is just an arbitrary number, it can be whatever is appropriate.

It would be real nice, however, if VFP had some function to show what low-level (User-opened) files are open and what their handles are.
Take a look at this code sample -- Using File Mapping to enumerate files opened by VFP at http://www.news2news.com/vfp/?example=473. -- Anatoliy Mogylevets
I use an object to close file handles when they go out of scope:
DEFINE CLASS file_closer as Custom
  PROTECTED nFile

  PROCEDURE init
    LPARAMETERS nFile
    this.nFile = nFile
  ENDPROC

  PROCEDURE destroy
    FCLOSE(this.nFile)
  ENDPROC
ENDDEFINE

In a program, I might write:
PRIVATE nFile
PRIVATE oFile

nFile = FOPEN("c:\foo.txt")
IF nFile = -1
  THROW "Cannot open file"
ELSE
  oFile = CREATEOBJECT("file_closer", nFile)
ENDIF

THROW "File will close now"

This is most useful when dealing with exceptions. It is appropriate to let an exception propagate upwards until you are prepared to handle it--you just need to clean up as the call stack unwinds. -- John Westbrook
Contributors: Zahid Ali Alex Feldstein Laurent Dujat df
Category Code Samples Category VFP Functions
( Topic last updated: 2006.07.06 09:57:12 AM )