MPL Training
Lesson 9
Black Panther

Are we ready for data files?

-=-=-=-=-=-=-=-=-

This will probably be a longer lesson, as there is a lot I want to cover, so 
let's jump right in with some new functions.

fEof(Handle):Boolean

This function will check to see if your internal pointer within the file, is
at the end of the file. If it is, it will return 'true', else it will return
'false'. This is a great check to make sure you don't try reading past the end
of a file.

While Not fEof(fptr) Do
  fReadLn(fptr,Text)

FileExist(FileName:String):Boolean

If you want to check to see if a file or directory exists, this function can
be used. If the file/directory exists, it will return 'true'

If FileExist('banana.txt') Then WriteLn('The file exists!')

fPos(File):LongInt

This function will return the current position of the internal file pointer
within the file. The fPos function will only work for binary data files, which
we are working our way up to. :)

fSize(File):LongInt

The fSize function will give you the size of an opened binary data file.

fAssign(fptr,'text.txt',66)
fReset(fptr)
If IoResult=0 Then
Begin
  If fPos(Fptr) = fSize(fptr) Then
    WriteLn('End of file')
  fClose(fptr)
End

fSeek(fptr:File,Position:LongInt)

While you are working with binary data files, you will need to be able to move
from one record to the next, or find information within the file. The fSeek
function will let you move to a specific location to ensure you are getting the
correct information.

fAssign(fptr,'blah.dat',66)
fSeek(fptr,FileSize(1))

This partial example, will move the internal file pointer to the end of the 
file. It is doing this by using the FileSize function, which gives the size of
the file, and then fSeek is moving to that point.

SizeOf(Type):LongInt

This is a very useful function, as it will tell you, or the program, the size
of just about any type of named variable.

Records
Integers
Real
LongInt
Strings
...etc

Just use the function as: SizeOf(variable)

The following function will give you a better example of using this function.

fRead(File,Variable,Integer)

The fRead function is used to read information from a data file. The file is 
the pointer you used when opening the file. The variable is where you want to
read the information to. If you are reading a file of records, the variable 
would have to be a record containing the same variables, and be the same size.
The Integer is the size of the record you are reading.

Type FileInfo = Record
  Index  : Integer
  Name   : String[50]
  Data   : Integer
End

Var
  fptr   : File
  info   : FileInfo
  RecNo  : Integer=3

Begin
  fAssign(fptr,'file.dat',66)
  fReset(fptr)
  If IoResult=0 Then
  Begin
    fSeek(fptr,(RecNo-1)*SizeOf(Info))
    If Not fEof(fptr) Then
      fRead(fptr,Info,SizeOf(Info))
  End
  fClose(fptr)
End

In this example, you have a record containing three variables. This record is 
assigned the name of 'info'. You then open the file, reset it, and check to 
make sure it opened correctly. Then the fSeek will move the internal pointer
to the beginning of the third record. (remember just about all counting in MPL
is 0 based, it doesn't start with 1) Then, while it's not at the end of the 
file it will read the record into the 'Info' record, and close the file.

fWrite(File,Variable,Integer)

Again, the write function is the opposite of read. When using the fWrite, which
will only work with a binary data file, you would tell it the name you gave the
file, what information you would like to write to the file, and the integer of
where you would like to saved.

Type FileInfo = record
  Index : Integer
  Name  : String [50]
  Data  : Integer
End

Var
  fptr : File
  info : FileInfo

  info.Index:=1
  info.Data:=33
  info.Name:='newname'

Begin
  fAssign(Fptr,'FILE.DAT',66)
  fReWrite(Fptr)
  fWrite(Fptr,Info,SizeOf(Info))
  fClose(Fptr)
End

In this example, we are opening the file 'FILE.DAT', which can be any type of
file as per the attributes, and giving it the name of Fptr. The next line is
rewriting the file, so if it contained information before, it will be lost. 
This will also create the file if it does not exist. We are then writing the
contents of the record named 'Info' to the file, and closing it.

I know I went through those functions a bit quicker than I probably should 
have, but I wanted to make sure I could give you a good working example of all
of these functions. 

The following example is what I have written in one of my MPL programs. This
shows how you would open a binary data file, seek the position within the file,
then read the information into a record.

Function ReadEntry(I:Integer):Boolean  //Takes an integer and returns a Boolean
Var
  Ret	: Boolean = False
  Fp	: File
Begin
	fAssign(Fp,ListName,66)    //Open our file with the name 'Fp'
	fReset(Fp)                 //Set the internal file pointer to the beginning
	If IoResult = 0 Then       //Check to make sure it opened correctly
	Begin
		fSeek(Fp,(I-1)*SizeOf(Entry)) //Seek the position of the record
		If Not fEof(Fp) Then          //Check to make sure we're not at the end
		Begin
			fRead(Fp,Entry,SizeOf(Entry))  //Read the record into 'Entry' record
      If Not Entry.Deleted Then      //If marked as deleted, ignore
			  Ret:=True                    //Return 'True', as we found the record
		End
		fClose(Fp)                       //Close your file *IMPORTANT*
	End
	ReadEntry:=Ret                     //Tell the function to return the Boolean
End

In this example, you'll notice it was called a function. That is because it is
returning a variable, in this case a Boolean. If it wasn't returning anything,
it would be called a procedure, as the next example does.

Procedure SaveEntry(I:Integer)   //Takes an Integer
Var Fp	: File                   //Assign our variable
Begin
	fAssign(Fp,ListName,66)        //Open the file using name of 'Fp'
	fReset(Fp)                     //Set internal file pointer to the beginning
	If IoResult <> 0 Then          //If the file did not open, do the following
		fReWrite(Fp)                 //This rewrites or creates the file
	Else 
		fSeek(Fp,(I-1)*SizeOf(Entry)) //Otherwise, it will search for the record
	fWrite(Fp,Entry,SizeOf(Entry))  //and write it to the file
	fClose(Fp)                      //Don't forget to close the file
End

Here is one more example. This one is from one of xqtr's MPLs. You'll notice 
that everyone develops their own style of coding, but the basics are very
similar.

Begin
  If Not FileExist(AddSlash(AppDir)+'ilc-bbs.dat') Then Exit;
  ResetScreen;
  fAssign(fp,AddSlash(AppDir)+'ilc-bbs.dat',66);
  fReset(fp);
  For p:=1 to 11 Do FillChar(Data[p],Sizeof(B),#0);
  p:=0;
  While Not fEOF(fp) Do Begin
    fReadRec(fp,Data[11]);
    Sort;
  End;
  fClose(fp);
End

Here, he is checking to see if the file exists. If it doesn't, it will exit.
The ResetScreen is another function within his MPL program. He then opens the
file with the fAssign, and gives it the name 'fp'. (we all have these orignal
names for the files, don't we?) He then resets the pointer. He then fills the
records with the #0, which is a null character.

He then reset's the variable 'p' to zero. Then he reads the records from the 
file, up to 11, and then sorts them with another function within his program. 

So, you can see there are many different things you can do with these files, 
but as I said, the basics are the same. You assign the file (open it), then
set the internal pointer to the beginning, then either read, write or both, and
then close your file.

While we did got through this information pretty quickly, I hope you have a bit
more understanding of how binary data files work, and can see how they can be
a bit tricky to get a grasp on, but overall are pretty simple to work with.

I did want to also mention, if you have a binary data file that you want to 
make sure your data saved properly, take a look at it with a hex editor. Most 
of them will show you the hex on the left side, and the character 
representation on the right side of the screen. This will show you how much 
you have allocated for each variable, along with the contents of those 
variables. After a bit of practice, you'll be using hex editors and data files
like a pro! :)
