Thursday, August 21, 2008

Manipulating files in your system

Manipulating files in your system

Several common file operations are built into the runtime library (RTL). The routines for working with files operate at a high level. For most routines, we have to specify the name of the file and the routine makes the necessary calls to the operating system for us. In some cases, we have to use file handles instead.

We have runtime library routines to perform following file manipulation tasks:

  1. Checking a file
  2. Deleting a file
  3. Finding a file
  4. Renaming a file
  5. File date-time routines
  6. Copying a file

File exists ?

To check whether a file exists or not in your system, you can use FileExists command. You have to pass filename with full path information as a parameter. The function returns True if it
finds the file in the system or returns False.

Delete File

Deleting a file erases the file from the disk and removes the entry from the disk's
directory. There is no corresponding operation to restore a deleted file, so applications
should generally allow users to confirm before deleting files. To delete a file, pass the
name of the file to the DeleteFile function:
DeleteFile(FileName);

DeleteFile returns True if it deleted the file and False if it did not (for example, if the
file did not exist or if it was read-only). DeleteFile erases the file named by FileName
from the disk.

Find file

There are three routines used for finding a file: FindFirst, FindNext, and FindClose.
FindFirst searches for the first instance of a filename with a given set of attributes in a
specified directory. FindNext returns the next entry matching the name and attributes
specified in a previous call to FindFirst. FindClose releases memory allocated by FindFirst. You should always use FindClose to terminate a FindFirst/FindNext sequence.
The three file find routines take a TSearchRec as one of the parameters. TSearchRec defines
the file information searched for by FindFirst or FindNext. If a file is found, the fields
of the TSearchRec type parameter are modified to describe the found file.

See the structure of the TsearchRec.


type

TFileName = string;

TSearchRec = record

Time: Integer; //Time contains the time stamp of the file.

Size: Integer; //Size contains the size of the file in bytes.

Attr: Integer; //Attr represents the file attributes of the file.

Name: TFileName; //Name contains the filename and extension.

ExcludeAttr: Integer;

FindHandle: THandle;

FindData: TWin32FindData; //FindData contains additional information such as

end;


Attr of TSearchRec is one of the commonly used property. You can test Attr against the
following attribute constants to determine if a file has a specific attribute:


Attribute Constant - Description

-------------------------------------------

faReadOnly - Read only files

faHidden - Hidden files

faSysFile - System files

faVolumeID -Volume ID files

faDirectory -Directory files

faArchive -Archive files

faAnyFile -Any file

Eg :
If the found file is a hidden file, the following expression will evaluate to True:
(SearchRec.Attr and faHidden > 0).

To search for read-only and hidden files in addition to normal files, pass the following as
the Attr parameter : (faReadOnly or faHidden).

See the following code to illustrate the use of all the 3 file finding code.

var SearchRec: TSearchRec;
while (True) do

begin

FindFirst('c:\MyFolder\*.*', faAnyFile, SearchRec);

Memo1.Add(SearchRec.Name + ' is ' + IntToStr(SearchRec.Size) + ' bytes in size');

if FindNext(SearchRec) = 0 then

Memo1.Add(SearchRec.Name + ' is ' + IntToStr(SearchRec.Size) + ' bytes in size')

else

begin

FindClose(SearchRec);

Break;

end;

end;


Rename File

To change a file name, you can use the RenameFile function. Syntax is
function RenameFile(const OldFileName, NewFileName: string): Boolean;
RenameFile changes a file name, identified by OldFileName, to the name specified by
NewFileName. If the operation succeeds, RenameFile returns True. If it cannot rename the
file (for example, if a file called NewFileName already exists), RenameFile returns False.
For example:
if not RenameFile('OLDNAME.TXT','NEWNAME.TXT') then ErrorMsg('Error renaming file!');
You cannot rename (move) a file across drives using RenameFile. You would need to first copy
the file and then delete the old one.


File date-time routines

The FileAge, FileGetDate, and FileSetDate routines operate on operating system date-time
values. FileAge returns the date-and-time stamp of a file, or -1 if the file does not exist.
FileSetDate sets the date-and-time stamp for a specified file, and returns zero on success
or an error code on failure. FileGetDate returns a date-and-time stamp for the specified
file or -1 if the handle is invalid.
As with most of the file manipulating routines, FileAge uses a string filename. FileGetDate
and FileSetDate, however, use a Handle type as a parameter. To get the file handle either:
1.Use the FileOpen or FileCreate function to create a new file or open an existing file.
Both FileOpen and FileCreate return the file handle.
2.Instantiate TFileStream to create or open a file. Then use its Handle property.


Copy File

The runtime library does not provide any routines for copying a file. However, if you are
writing Windows-only applications, you can directly call the Windows API CopyFile function
to copy a file. Similar to most of the runtime library file routines, CopyFile takes a
filename as a parameter, not a file handle. CopyFile is also useful when moving files across
drives because neither the RenameFile function nor the Windows API MoveFile function can
rename or move files across drives.

Delphi provides a number of different file access mechanisms. The oldest is in support of
consoles, where the Read, ReadLn, Write and WriteLn routines have a syntax that omits the
file name. With no file name, IO (Input and Output) is routed to the console. Additionally, hidden away, Delphi provides a very elegant way of reading and writing complete text files. The TStringList class has methods for loading the list of strings from a text file. And for saving the list likewise.

Accessing files

There are a number of basic operations for handling both text and binary files.

var

myFile : TextFile;

begin

AssignFile(myFile, 'Test.txt');

Here we are getting a handle to a text file, designated by the TextFile type (binary files
are of type File). We ask Delphi to assign a file handle for a file called 'Test.txt' which
will be assumed to be in the current directory.If the file exists in some other folder , you
can specify the whole path within the quotes. Next, we must open the file using this handle. This operation tells Delphi how we want to treat the file. There are 3 ways of opening the file:

ReWrite - Opens a file as new - discards existing contents if file exists

Reset - Opens a file for read and write access

Append - Opens a file for appending to the end (such as a log file)

When we have finished, we must close the file using the command : CloseFile(myFile);

Reading and writing to text files

You can any of the following commands to read from and write to the file.
Read : Reads the current line . File Pointer won't move to next line

ReadLn : Reads current line and file pointer moves to the next line.

Write : Write string to the file , But file pointer won't move to next line.

WriteLn : Writes data to file and file pointer moves to next line.
Here is a simple example of access to a text file:

var

myFile : TextFile;

text : string;

begin

AssignFile(myFile, 'Test.txt');

ReWrite(myFile);

WriteLn(myFile, 'Hello');

WriteLn(myFile, 'World');

CloseFile(myFile);

Reset(myFile); // Reopen the file for reading

while not Eof(myFile) do

begin

ReadLn(myFile, text);

ShowMessage(text);

end;

CloseFile(myFile);

end;

The ShowMessage routine displays the following :

Hello

World

If we replaced the ReWrite routine with Append, and rerun the code, the existing file would
then contain:

Hello

World

Hello

World

Reading and writing to typed binary files

Typed binary files are files that have a data type as the basic unit of writing and reading.
You write, say, an Integer, or a Record to a file, and read the same unit of data back.
Records are particularly useful, allowing us to store any mix of data types in the one file
unit of data. This is best illustrated with an example:

type

TCustomer = Record

name : string[20];

age : Integer;

male : Boolean;

end;

var

myFile : File of TCustomer; // A file of customer records

customer : TCustomer; // A customer record variable

begin

AssignFile(myFile, 'Test.cus');

ReWrite(myFile);

customer.name := 'Fred Bloggs';

customer.age := 21;

customer.male := true;

Write(myFile, customer);

customer.name := 'Jane Turner';

customer.age := 45;

customer.male := false;

Write(myFile, customer);

CloseFile(myFile);

FileMode := fmOpenRead;

Reset(myFile);

while not Eof(myFile) do

begin

Read(myFile, customer);

if customer.male

then

ShowMessage('Man with name '+customer.name+ ' is '+IntToStr(customer.age))

else ShowMessage('Lady with name '+customer.name+ ' is '+IntToStr(customer.age));

end;

CloseFile(myFile);

end;

Output : Man with name Fred Bloggs is 21

Lady with name Jane Turner is 45
The code is very similar to that used for text files, except that we define a file of a
certain type (record), and pass/receive record data when writing/reading.

Reading and writing to pure binary files

Pure binary files are a bit peculiar. You must use BlockRead and BlockWrite instead of Read
and Write. These have the added benefit of greater performance than the Read and Write.

Here is an example :

var

myFile : File;

byteArray : array[1..8] of byte;

oneByte : byte;

i, count : Integer;

begin

AssignFile(myFile, 'Test.byt');

ReWrite(myFile, 4); // Define a single 'record' as 4 bytes

for i := 1 to 8 do

byteArray[i] := i;

BlockWrite(myFile, byteArray, 2); // Write 2 'records' of 4 bytes

// Fill out the data array with different data

for i := 1 to 4 do byteArray[i] := i*i; // Value : 1, 4, 9, 16

BlockWrite(myFile, byteArray, 1); // Write 1 record of 4 bytes

CloseFile(myFile);

FileMode := fmOpenRead;

Reset(myFile, 1);

ShowMessage('Reading first set of bytes :');

BlockRead(myFile, byteArray, 6, count); // Display the byte values read

for i := 1 to count do

ShowMessage(IntToStr(byteArray[i]));

ShowMessage('Reading remaining bytes :');

while not Eof(myFile) do

begin

BlockRead(myFile, oneByte, 1); // Read and display one byte at a time

ShowMessage(IntToStr(oneByte));

end;

CloseFile(myFile);

end;

Getting information about files and directories

There are a number of routines that allow you to do all sorts of things with files and
directories that contain them:

ChDir : Change the working drive plus path for a specified drive

CreateDir : Create a directory

Erase : Erase a file

FileSearch : Search for a file in one or more directories

FileSetDate : Set the last modified date and time of a file

Flush : Flushes buffered text file data to the file

GetCurrentDir : Get the current directory (drive plus directory)

MkDir : Make a directory

RemoveDir : Remove a directory

Rename : Rename a file

RmDir : Remove a directory

SelectDirectory : Display a dialog to allow user selection of a directory

SetCurrentDir : Change the current directory

Truncate : Truncates a file size

Using TStringList to read and write text files

The TStringList class is a very useful utility class that works on a lits of strings, each
indexable like an array. The list can be sorted, and supports name/value pair strings,
allowing selection by name or value. These lists can be furnished from text files. Here we show a TStringList object being created, and loaded from a file:

var

fileData : TStringList; // Our TStringList variable

begin

fileData := TStringList.Create; // Create the TSTringList object

fileData.LoadFromFile('Testing.txt'); // Load from Testing.txt file ...

We can display the whole file in a Memo box : memoBox.Text := fileData.Text;
Similarly you can use the SaveToFile command to save the whole strings stored inside the
String List to a text file.
Eg: fileData.SaveToFile('Test.txt'); // Save the reverse sequence file

No comments: