Difference between revisions of "File Handling In Pascal"

From Lazarus wiki
Jump to navigationJump to search
m (Old procedural style: change nonobjective to non-object oriented to avoid confusion with Objective Pascal)
(Example procedural program mixed $I+ and $I- style of error handling. Changed to exception handling as that seemed easiest.)
Line 1: Line 1:
 
{{File Handling In Pascal}}
 
{{File Handling In Pascal}}
  
Something most programmers need to know how to do is work with files. Files can be used to save user settings, error logs, and more. Here i am going to teach you how to work with basic text files.
+
Something most programmers need to know how to do is work with files. Files can be used to save user settings, error logs, and more. Here I am going to teach you how to work with basic text files.
  
 
=Old procedural style=
 
=Old procedural style=
  
When using files in classic (non-object oriented) pascal, you can use a TextFile type, which allows you to write string into the file or create your own file type.
+
When using files in classic (non-object oriented) Pascal, you can use a TextFile type, which allows you to write string into the file or create your own file type.
  
 
<Delphi>...
 
<Delphi>...
Line 11: Line 11:
 
  TIntegerFile = file of Integer; // Allows you to write Integers into the file
 
  TIntegerFile = file of Integer; // Allows you to write Integers into the file
 
  TPCharFile = file of PChar; // Write PChars into the file :\
 
  TPCharFile = file of PChar; // Write PChars into the file :\
  TStringFile = file of string; // Write Strings into the file
+
  TStringFile = file of String; // Write Strings into the file
 
...</Delphi>
 
...</Delphi>
  
Line 18: Line 18:
 
==IO==
 
==IO==
  
IO is the file handling thingy for pascal. It is used for getting errors.
+
IO is the file handling thingy for Pascal. It tells the compiler how to deal with IO error situations: raise an exception or store the result into the IOResult variable.
 
Since it is a compiler directive, you have to do this:
 
Since it is a compiler directive, you have to do this:
 
<Delphi>{$I-} // Turn off checking. This way all errors go into the IOResult variable
 
<Delphi>{$I-} // Turn off checking. This way all errors go into the IOResult variable
{$I+} // Turn it back on</Delphi>
+
{$I+} // Turn it back on; errors will lead to an EInOutError exception
 +
</Delphi>
  
By disabling (Turning off) IO it all goes into the IOResult variable. This is an cardinal type(Numbers). So, if you want to write it, you have to use the IntToStr function. Different numbers mean different errors. So you may want to check here for the different errors: [http://www.efg2.com/Lab/Library/Delphi/IO/IOResult.htm]
+
By disabling/turning off $I, file operation results go into the IOResult variable. This is a cardinal type (Numbers). So, if you want to write IOResult, you have to use the IntToStr function. Different numbers mean different errors. So you may want to check the documentation for the different errors: [http://www.freepascal.org/docs-html/rtl/system/ioresult.html].
  
 
==File procedures==
 
==File procedures==
  
These file handling procedures and functions are located in unit system.
+
These file handling procedures and functions are located in unit system. See the FPC documentation for more details: [http://www.freepascal.org/docs-html/rtl/system/index-5.html Reference for 'System' unit].
  
 
* '''Assign''' - Assign a name to a file
 
* '''Assign''' - Assign a name to a file
Line 51: Line 52:
 
* '''WriteLn''' - Write variable to a text file and append newline
 
* '''WriteLn''' - Write variable to a text file and append newline
  
 
[http://www.freepascal.org/docs-html/rtl/system/index-5.html Reference for unit 'System']
 
  
 
==Example==
 
==Example==
Line 71: Line 70:
 
   WriteLn('File Test');
 
   WriteLn('File Test');
 
   AssignFile(FileVar, 'Test.txt'); // You do not have to put .txt but this is just for now
 
   AssignFile(FileVar, 'Test.txt'); // You do not have to put .txt but this is just for now
   {$I-}
+
   {$I+} //use exceptions
   try
+
   try
     Rewrite(FileVar);  // creating the file
+
     Rewrite(FileVar);  // creating the file
 
     Writeln(FileVar,'Hello');
 
     Writeln(FileVar,'Hello');
 +
    CloseFile(FileVar);
 
   except
 
   except
     Writeln('ERROR! IORESULT: ' + IntToStr(IOResult));
+
     on E: EInOutError do
 +
    begin
 +
    Writeln('File handling error occurred. Details: '+E.ClassName+'/'+E.Message);
 +
    end;   
 
   end;
 
   end;
   CloseFile(FileVar);
+
   WriteLn('Program finished. Press enter to stop.');
 
   ReadLn;
 
   ReadLn;
 
end.</Delphi>
 
end.</Delphi>
  
 
Now open the file in any text editor and you will see Hello written to it!
 
Now open the file in any text editor and you will see Hello written to it!
 +
You can test the error handling by running it once, setting test.txt to read-only and try running it again.
 +
 +
Note that we used exception handling ({$I+}) as that is an easy way to perfom multiple file operations and handling the errors. You could also use {$I-}, but then you would have to check IOResult after each operation and modify your next operation.
  
Heres appending to a file(Editing it)
+
Here's how appending/adding to a file works:
  
 
<Delphi>program EditFile;
 
<Delphi>program EditFile;
Line 99: Line 105:
 
begin
 
begin
 
   WriteLn('Append file');
 
   WriteLn('Append file');
  AssignFile(File1, 'File.txt');
+
   {$I+}
   {$I-}
 
 
   try
 
   try
     Append(File1, 'Some Text');
+
    AssignFile(File1, 'File.txt');
 +
     Append(File1, 'adding some text...');
 +
    CloseFile(File1);
 
   except
 
   except
     Writeln('ERROR IORESULT:' + IntToStr(IOResult));
+
     on E: EInOutError do
 +
    begin
 +
    Writeln('File handling error occurred. Details: '+E.ClassName+'/'+E.Message);
 +
    end;   
 
   end;
 
   end;
   {$I+}
+
   WriteLn('Program finished. Press enter to stop.');
  CloseFile(File1);
 
 
   Readln;
 
   Readln;
 
end.</Delphi>
 
end.</Delphi>
Line 128: Line 137:
 
   Writeln('File Reading:');
 
   Writeln('File Reading:');
 
   AssignFile(File1, 'File.txt');
 
   AssignFile(File1, 'File.txt');
   {$I-}
+
   {$I+}
 
   try
 
   try
 
     Reset(File1);
 
     Reset(File1);
Line 135: Line 144:
 
       Writeln(Str); // Writes the line read
 
       Writeln(Str); // Writes the line read
 
     until(EOF(File1)); // EOF(End Of File) The the program will keep reading new lines until there is none.
 
     until(EOF(File1)); // EOF(End Of File) The the program will keep reading new lines until there is none.
 +
    CloseFile(File1);
 
   except
 
   except
     Writeln('ERROR IORESULT:', IOResult);
+
     on E: EInOutError do
 +
    begin
 +
    Writeln('File handling error occurred. Details: '+E.ClassName+'/'+E.Message);
 +
    end;   
 
   end;
 
   end;
   {$I+}
+
   WriteLn('Program finished. Press enter to stop.');
  CloseFile(File1);
 
 
   Readln;
 
   Readln;
 
end.</Delphi>
 
end.</Delphi>
Line 147: Line 159:
 
=Object style=
 
=Object style=
  
Most of string handling classes have ability to load and save content from/to file. These methods are usually named SaveToFile and LoadFromFile.
+
Most of string handling classes have the ability to load and save content from/to file. These methods are usually named SaveToFile and LoadFromFile. A lot of other objects (such as Lazarus grids) have similar functionality, including Lazarus datasets (DBExport); it pays to look through the documentation/source code before trying to roll your own import/export routines.
  
 
==Binary files==
 
==Binary files==
  
For opening files for direct access TFileStream should be used. This class is encapsulation for system procedures FileOpen, FileCreate, FileRead, FileWrite, FileSeek and FileClose which resides in unit FileUtil. This class is basically platform independent as these procedures have specific implementation for each platform.
+
For opening files for direct access TFileStream should be used. This class is an encapsulation of system procedures FileOpen, FileCreate, FileRead, FileWrite, FileSeek and FileClose which resides in unit FileUtil. This class is basically platform independent as these procedures have specific implementations for each platform.
  
 
[http://www.freepascal.org/docs-html/rtl/sysutils/ioroutines.html IO routines]
 
[http://www.freepascal.org/docs-html/rtl/sysutils/ioroutines.html IO routines]
  
 +
In the example below, note how we encapsulate the file handling action with a try..finally block. This makes sure the Filestream object is always released (the finally... part) even if there are file access (or other) errors.
 
<Delphi>var
 
<Delphi>var
 
   Buffer: array[0..10000] of Byte;
 
   Buffer: array[0..10000] of Byte;
Line 168: Line 181:
  
  
You can load entire file to memory too if it's size is comparatively smaller than available system memory.
+
You can load entire files into memory too if its size is comparatively smaller than available system memory. Bigger sizes might work but your operating system will start using the page/swap file, making the exercise useless from a performance standpoint.
  
 
<Delphi>begin
 
<Delphi>begin
Line 185: Line 198:
 
==Text files==
 
==Text files==
  
In general for text files you can use class TStringList for loading entire file to memory and have simple access their rows.
+
In general for text files you can use the TStringList class to load the entire file into memory and have simple access to their lines. Of course, you can also save your StringList back to file:
  
 
<Delphi>begin
 
<Delphi>begin

Revision as of 13:22, 23 November 2011

العربية (ar) English (en) español (es) suomi (fi) français (fr) 日本語 (ja) русский (ru) 中文(中国大陆)‎ (zh_CN) 中文(台灣)‎ (zh_TW)

Something most programmers need to know how to do is work with files. Files can be used to save user settings, error logs, and more. Here I am going to teach you how to work with basic text files.

Old procedural style

When using files in classic (non-object oriented) Pascal, you can use a TextFile type, which allows you to write string into the file or create your own file type.

<Delphi>... type

TIntegerFile = file of Integer; // Allows you to write Integers into the file
TPCharFile = file of PChar; // Write PChars into the file :\
TStringFile = file of String; // Write Strings into the file

...</Delphi>

If we only did TStringFile = File, then it would be impossible to write anything into it! Also, you cannot write integers directly into TStringFile, because it is a file of strings. Better use the filetype TextFile for writing values of different types.

IO

IO is the file handling thingy for Pascal. It tells the compiler how to deal with IO error situations: raise an exception or store the result into the IOResult variable. Since it is a compiler directive, you have to do this: <Delphi>{$I-} // Turn off checking. This way all errors go into the IOResult variable {$I+} // Turn it back on; errors will lead to an EInOutError exception </Delphi>

By disabling/turning off $I, file operation results go into the IOResult variable. This is a cardinal type (Numbers). So, if you want to write IOResult, you have to use the IntToStr function. Different numbers mean different errors. So you may want to check the documentation for the different errors: [1].

File procedures

These file handling procedures and functions are located in unit system. See the FPC documentation for more details: Reference for 'System' unit.

  • Assign - Assign a name to a file
  • Append - Opens an existing file for appending data to end of file and editing it
  • BlockRead - Read data from an untyped file into memory
  • BlockWrite - Write data from memory to an untyped file
  • Close - Close opened file
  • EOF - Check for end of file
  • Erase - Erase file from disk
  • FilePos - Get position in file
  • FileSize - Get size of file
  • Flush - Write file buffers to disk
  • IOResult - Return result of last file IO operation
  • Read - Read from a text file into variable
  • ReadLn - Read from a text file into variable and goto next line
  • Reset - Opens a file for reading
  • Rewrite - Open file for writing
  • Seek - Change position in file
  • SeekEOF - Set file position to end of file
  • SeekEOLn - Set file position to end of line
  • Truncate - Truncate the file at position
  • Write - Write variable to a text file
  • WriteLn - Write variable to a text file and append newline


Example

A full example of handling a text file of type TextFile:

<Delphi>program FileTest;

{$mode objfpc} // Do not forget this ever

uses

Sysutils;

var

FileVar: TextFile;

begin

 WriteLn('File Test');
 AssignFile(FileVar, 'Test.txt'); // You do not have to put .txt but this is just for now
 {$I+} //use exceptions
 try  
   Rewrite(FileVar);  // creating the file  
   Writeln(FileVar,'Hello');
   CloseFile(FileVar);
 except
   on E: EInOutError do
   begin
    Writeln('File handling error occurred. Details: '+E.ClassName+'/'+E.Message);
   end;    
 end;
 WriteLn('Program finished. Press enter to stop.');  
 ReadLn;

end.</Delphi>

Now open the file in any text editor and you will see Hello written to it! You can test the error handling by running it once, setting test.txt to read-only and try running it again.

Note that we used exception handling ({$I+}) as that is an easy way to perfom multiple file operations and handling the errors. You could also use {$I-}, but then you would have to check IOResult after each operation and modify your next operation.

Here's how appending/adding to a file works:

<Delphi>program EditFile;


{$mode objfpc}

uses

Sysutils;

var

File1: TextFile;

begin

 WriteLn('Append file');
 {$I+}
 try
   AssignFile(File1, 'File.txt');
   Append(File1, 'adding some text...');
   CloseFile(File1);
 except
   on E: EInOutError do
   begin
    Writeln('File handling error occurred. Details: '+E.ClassName+'/'+E.Message);
   end;    
 end;
 WriteLn('Program finished. Press enter to stop.');  
 Readln;

end.</Delphi>

Reading a file:

<Delphi>program ReadFile;


{$mode objfpc}

uses

Sysutils;

var

File1: TextFile;
Str: String;

begin

 Writeln('File Reading:');
 AssignFile(File1, 'File.txt');
 {$I+}
 try
   Reset(File1);
   repeat
     Readln(File1, Str); // Reads the whole line from the file
     Writeln(Str); // Writes the line read
   until(EOF(File1)); // EOF(End Of File) The the program will keep reading new lines until there is none.
   CloseFile(File1);
 except
   on E: EInOutError do
   begin
    Writeln('File handling error occurred. Details: '+E.ClassName+'/'+E.Message);
   end;    
 end;
 WriteLn('Program finished. Press enter to stop.');  
 Readln;

end.</Delphi>

It is possible to do some file handling using chars instead of strings. This makes it look cool :D.

Object style

Most of string handling classes have the ability to load and save content from/to file. These methods are usually named SaveToFile and LoadFromFile. A lot of other objects (such as Lazarus grids) have similar functionality, including Lazarus datasets (DBExport); it pays to look through the documentation/source code before trying to roll your own import/export routines.

Binary files

For opening files for direct access TFileStream should be used. This class is an encapsulation of system procedures FileOpen, FileCreate, FileRead, FileWrite, FileSeek and FileClose which resides in unit FileUtil. This class is basically platform independent as these procedures have specific implementations for each platform.

IO routines

In the example below, note how we encapsulate the file handling action with a try..finally block. This makes sure the Filestream object is always released (the finally... part) even if there are file access (or other) errors. <Delphi>var

 Buffer: array[0..10000] of Byte;

begin

 with TFileStream.Create('SomeFile.bin', fmCreate) do 
 try
   Seek('Hello');
   Write(Buffer, SizeOf(Buffer));
 finally
   Free;
 end;

end;</Delphi>


You can load entire files into memory too if its size is comparatively smaller than available system memory. Bigger sizes might work but your operating system will start using the page/swap file, making the exercise useless from a performance standpoint.

<Delphi>begin

 with TMemoryStream.Create do 
 try
   LoadFromFile('SomeFile.bin');
   Seek(0, soEnd);
   Write(Ord('A'), 1);
   SaveToFile('SomeFile.bin');
 finally
   Free;
 end;

end;</Delphi>


Text files

In general for text files you can use the TStringList class to load the entire file into memory and have simple access to their lines. Of course, you can also save your StringList back to file:

<Delphi>begin

 with TStringList.Create do 
 try
   Add('Hello');
   SaveToFile('SomeFile.txt');
 finally
   Free;
 end;

end;</Delphi>