Reading and writing text files

How do I read from and write to text files using Delphi?

Note: There's a demonstration program accompanying this article.

One of the most basic operations in practically any language is working with text files. I realize this is probably old hat to many of the more experienced programmers out there, but there are a lot of novice Delphi programmers who don't know how to work with text files at all. Several people have asked me how to open, read, and write text files, so in response to their queries, I've decided to write a quick article on the subject.

In particular, people have asked me how to read a text file into a TMemo, then write its contents back to the file. The easy way to do this is with the TMemo's Lines property LoadFromFile and SaveToFile methods. Just provide a file name and poof! the file's loaded into a memo. Here are a couple of quick functions that I use to read text files into a TMemo (or any component that has a property of type TStrings).

{This procedure loads any TStrings type property with the contents
 of a text file}
procedure TextToTStrings(const List : TStrings; const FileName : String);
  with List do begin

{This procedure saves the contents of any TStrings type property to a
 text file}
procedure TStringsToText(const List : TStrings; const FileName : String);
  with List do

As you can see, the procedures are practically one-liners. While they don't seem too interesting, there is one thing about them that you should note. If you look at the code above, the first formal parameter of each of the procedures, const List : TStrings, is a TStrings type passed as a const. This is the only way you can pass a TStrings type as a formal parameter into a function or procedure. You can't pass by reference (passing by var); you'll get a compiler error. This is because unlike a variable that is of a standard type such as String or Integer, a TStrings type variable is actually an instance which, in effect, makes it a constant object. Thus, in order to use it as a formal parameter, you have to pass it as a const. Okay, onward ho!

The two functions above, while useful, didn't really serve to answer the question, though they are the way to quickly and easily load from and save to text files using TMemos. Why did I go that route in the first place? Primarily because most people have asked me that question within the context of a TMemo, so I thought I'd tackle that problem first and foremost, then get down to basic text file I/O.

Working with text files

Delphi provides an incredibly easy way to write a program that reads and writes a text file. To do this, you perform five basic steps:

  1. Declare a variable of type TextFile or System.Text
  2. Assign a physical text file to the variable
  3. Open the file within a specific file mode context
  4. Read and write to the file as appropriate
  5. Close the file

The first thing you do is declare a text file variable as follows:

  txt : TextFile;

However, System.Text is just as valid. If you do it this way though, you have to always qualify the word Text with the unit identifier System because a form's unit already contains a Text variable, so you have to point the variable declaration to the proper place. Personally, I find that simply declaring a text file variable as TextFile avoids this problem entirely. I suggest using it instead.

After you've declared the text file, you have to assign the variable to a text file. This is done as follows:

AssignFile(txt, 'MyText.TXT');

Similarly to declaring a text file variable, you can also do a System.Assign(txt, 'MyText.TXT');. But for the same reason I explained above, it's better to use AssignFile. Finally, you have to decide how you want to manipulate the text file. This is done using one of the following three file-opening functions:

Rewrite This creates a file or overwrites an existing file.
Reset This opens an existing file.
Append This opens an existing file, but allows you to append strings to the end of it as well.

Once you've opened the file, you're ready to perform reads and writes. Using the example I outlined above, I'll show you how to read from a text file into a TMemo and write to a text file from a TMemo.

Let's look at reading a text file first. The following procedures, IterTextToTStrings and IterTStringsToText, produce the exact same results as above, but use file I/O functions instead. I've preceded their names with the prefix Iter- to indicate that these procedures employ an iterative methodology for loading in the lines of a text file. Let's look at the code:

{Procedure to read a text file into a TMemo}
procedure IterTextToTStrings(Wnd : THandle; const List : TStrings;
                             const FileName : String);
  txt : TextFile;
  buf : String;
  AssignFile(txt, FileName);
  {Do a LockWindowUpdate to delay the screen updates while the
   lines are being added. This will prevent visible scrolling
   during the process.}
  while NOT EOF(txt) do begin
    ReadLn(txt, buf);    

{Procedure to write a TMemo's contents to a file}
procedure IterTStringsToText(const List : TStrings; const FileName : String);
  txt : TextFile;
  I   : Integer;
  if FileExists(FileName) then
    if (MessageDlg('File ' + FileName + ' exists. Overwrite?', mtConfirmation,
        [mbOk, mbCancel], 0) = mrCancel) then

  AssignFile(txt, FileName);
  for I := 0 to (List.Count - 1) do begin
    WriteLn(txt, List[I]);  

I've put in boldface the file operation you should pay attention to in each of the procedures. In the first procedure, I've employed the ReadLn function that reads a line from a text file, then performs a line feed to point the file to the next line. ReadLn takes two parameters: the text file variable, and a String variable for receiving the current line's contents. Note that once you've loaded a line into a string variable, you can do everything to it that you can do to a string. In our case, we load it as a line of a TMemo.

In the second procedure, I've used the WriteLn function to write a line of text to a file. Like ReadLn above, WriteLn takes two parameters: the text file variable, and a valid string. If you don't have a properly filled string, you will probably get some weird results.

After the procedures above finish their basic I/O functions, CloseFile is called to close the file. This step is absolutely imperative. If you don't perform it, you'll get a file sharing violation error when you try to access this file - and that's from any program besides your own. So never forget this step!

There's an issue you should know about that concerns text files: You can't insert a line of text in the middle of an open text file, at least not very easily. You have three options: Create a new file, open an existing file, or append to an existing file. If you really need to insert a line, your best bet is to read the entire file as a an untyped or binary file into a dynamic array or a TList, insert the new line in the appropriate position, then write the entire contents of the array or list back out to the file. Needless to say, this is problematic at best.

Summing it up

What I've presented here is a very basic method of working with text files. However, the principle defined by the five steps I listed above is a constant. It's what you put in between the read and write operation that will make your program complex. In other words, from program to program, text file operations don't change.