11

What is the easiest way to create and save string into .txt files?

jonsca
  • 10,218
  • 26
  • 54
  • 62
micheal
  • 197
  • 1
  • 1
  • 5

6 Answers6

17

Use TStringList.

uses
  Classes, Dialogs; // Classes for TStrings, Dialogs for ShowMessage

var
  Lines: TStrings;
  Line: string;
  FileName: string;
begin
  FileName := 'test.txt';
  Lines := TStringList.Create;
  try
    Lines.Add('First line');
    Lines.Add('Second line');
    Lines.SaveToFile(FileName);
    Lines.LoadFromFile(FileName);
    for Line in Lines do
      ShowMessage(Line);
  finally
    Lines.Free;
  end;
end;

Also SaveToFile and LoadFromFile can take an additional Encoding in Delphi 2009 and newer to set the text encoding (Ansi, UTF-8, UTF-16, UTF-16 big endian).

Jens Mühlenhoff
  • 14,565
  • 6
  • 56
  • 113
  • 4
    Yes. This is by far the simplest way. Not only is the `TStringList` object very easy to work with and rather powerful, `TStrings` is also used throughout the entire VCL, so that all components can communicate with each other by assigning string lists. I just want to mention alternative ways of working with text files (all of them are more difficult than this, but just for the sake of completeness). See http://stackoverflow.com/questions/3538156/file-i-o-in-every-programming-language/3538227#3538227 – Andreas Rejbrand Nov 16 '10 at 11:24
  • 1
    Not the simplest in my opinion. The use of TextFile is easier... That is, if you're familiar with AssignFile/Reset/Rewrite/Append/Read/ReadLn/Write/WriteLn/CloseFile and SetTextBuf... ;-) – Wim ten Brink Nov 16 '10 at 12:55
  • 1
    The string list approach has the limit it is a huge buffer and data are written all at once. The old file interface IMHO is a "legacy" interface which should be superseeded by the new stream interface which is more actual and flexible. Maybe not the "easiest", but sometimes is better to use the "right" code, not the "easiest one" –  Nov 16 '10 at 13:19
  • @Workshop Alex, yeah classic Pascal are less easier maybe, but very high-level TStrings operations are not really about file I/O, but about general string collection manipulation – Free Consulting Nov 16 '10 at 13:32
  • @ldsandon, actually TStrings I/O requires ≈ 2×DataSize memory, and this has been assessed w/o taking recoding overhead into account. Streams are lacking support for the lines of text. – Free Consulting Nov 16 '10 at 13:34
  • I'd also advice against the old Pascal interface. If more control over I/O and resource usage is desired I would use `TFileStream`. For simple text files `TStringList` should be fine. – Jens Mühlenhoff Nov 16 '10 at 16:16
  • The old Pascal interface is far more powerful than most people suspect. It is a simple way to write text files but for experienced developers, the use of TTextRec combined with some other tricks will allow you to write (non-unicode) text to literally anything. (Files, printers, memo fields, TCP/IP, whatever...) – Wim ten Brink Nov 16 '10 at 16:32
  • 1
    I always use the `TextFile` approach personally. (Now I've said it.) – Andreas Rejbrand Nov 16 '10 at 16:49
  • @ user205376: streams are lacking support for lines of text **before** Delphi 2009. TStreamReader/TStreamWriter have support for line-oriented I/O, and better support for different enconding and line endings. Before that you can find some libraries (i.e. SysTools) adding "textfiles" support to streams. –  Nov 16 '10 at 18:06
  • 1
    @ldsandon, `TTextReader` is just .NOT mirror class and is way too clumsy for simple text I/O. Pascal `TextFile` wins her. – Free Consulting Nov 17 '10 at 09:43
  • @user205376: if you prefer to live in the past... :) Not everything in .NET is "bad", and the stream classes are far more flexibile. Also TextFile requires more calls and even different calls (reset/rewrite) to open a file for a given operation, while using a global variable to set the file access mode. It may *look* simpler, but in the long run you may discover it is not... –  Nov 18 '10 at 08:13
6

Actually, I prefer this:

var
  Txt: TextFile;
  SomeFloatNumber: Double;
  SomeStringVariable: string;
  Buffer: Array[1..4096] of byte;
begin
  SomeStringVariable := 'Text';
  AssignFile(Txt, 'Some.txt');
  Rewrite(Txt);
  SetTextBuf(Txt, Buffer, SizeOf(Buffer));
  try
    WriteLn(Txt, 'Hello, World.');
    WriteLn(Txt, SomeStringVariable);
    SomeFloatNumber := 3.1415;
    WriteLn(Txt, SomeFloatNumber:0:2); // Will save 3.14
  finally CloseFile(Txt);
  end;
end;

I consider this the easiest way, since you don't need the classes or any other unit for this code. And it works for all Delphi versions including -if I'm not mistaken- all .NET versions of Delphi...


I've added a call to SetTextBuf() to this example, which is a good trick to speed up textfiles in Delphi considerably. Normally, textfiles have a buffer of only 128 bytes. I tend to increase this buffer to a multiple of 4096 bytes. In several cases, I'va also implemented my own TextFile types, allowing me to use these "console" functions to write text to memo fields or even to another, external application! At this location is some example code (ZIP) I wrote in 2000 and just modified to make sure it compiles with Delphi 2007. Not sure about newer Delphi versions, though. Then again, this code is 10 years old already.
These console functions have been a standard of the Pascal language since it's beginning so I don't expect them to disappear anytime soon. The TtextRec type might be modified in the future, though, so I can't predict if this code will work in the future... Some explanations:

  • WA_TextCustomEdit.AssignCustomEdit allows text to be written to CustomEdit-based objects like TMemo.
  • WA_TextDevice.TWATextDevice is a class that can be dropped on a form, which contains events where you can do something with the data written.
  • WA_TextLog.AssignLog is used by me to add timestamps to every line of text.
  • WA_TextNull.AssignNull is basically a dummy text device. It just discards anything you write to it.
  • WA_TextStream.AssignStream writes text to any TStream object, including memory streams, file streams, TCP/IP streams and whatever else you have.

Code in link is hereby licensed as CC-BY alt text


Oh, the server with the ZIP file isn't very powerful, so it tends to be down a few times every day. Sorry about that.

Wim ten Brink
  • 25,901
  • 20
  • 83
  • 149
  • 6
    Please, beware that the console operations (like read and write, have unicode issues, so its recommended to use TStringList. – Toon Krijthe Nov 16 '10 at 12:57
  • 1
    To add to @Gamecat's comment: it is not just the console operations, but all file operations using the AsignFile, Rewrite, Read(Ln), Write(Ln) family of methods. The console operations are actually these file operations operating on a specific set of handles. – Marjan Venema Nov 16 '10 at 14:51
  • True, unicode is a bit of a problem. But using these functions means that you don't have to buffer the full text in memory before writing it to file. It has it's pro's and con's. – Wim ten Brink Nov 16 '10 at 15:06
  • You could of course use `OpenFile`, `CreateFile`, etc. from the Windows API. That gives you the maximum amount of control. – Jens Mühlenhoff Nov 16 '10 at 16:20
  • True, but then you'd have to write more complex code to write the strings. Btw, I also wonder if Embarcadero will alter the TextFile code to support unicode in the near future. Judging from the TTextRec type in the system unit, it will probably not support unicode any moment soon. – Wim ten Brink Nov 16 '10 at 16:29
  • I guess they won't given what TStreamReader/TStreamWriter can do since Delphi 2009. –  Nov 16 '10 at 18:07
  • 1
    @Gamecat & Workshop Alex, Read/Write[ln] are binary-safe, thus it is possible to make them read and write wide strings – Free Consulting Nov 17 '10 at 09:48
  • In my tests, the AssignFile ... CloseFile method is a lot slower than using string lists ... and I mean A LOT slower. – Edelcom Nov 17 '10 at 15:17
  • @Edelcom, then use SetTextBuf() to increase the text buffer for the file: `var Buffer: array[1..4096] of byte; Txt: TextFile;begin AssignFile(Txt, 'example.txt');Rewrite(Txt);SetTextBuf(Txt, Buffer, SizeOf(Buffer);WriteLn(Txt, ...` – Wim ten Brink Nov 18 '10 at 08:22
  • @Gamecat, it's just that I haven't tested if Textfiles support Unicode. I don't think it would be too difficult to create a TextFile type that will support unicode, though. – Wim ten Brink Nov 18 '10 at 09:10
  • 1
    In newer Delphi versions the classic I/O routines have got some support for Unicode again. Delphi XE added a new Codepage parameter, see also this question: http://stackoverflow.com/questions/14232900/unicode-text-file-output-differs-between-xe2-and-delphi-2009 – Jens Mühlenhoff Sep 18 '13 at 09:05
  • You will run into performance problems if you TStringList and the text file you want to read/write is big (over 50-100MB): http://stackoverflow.com/questions/35710087/how-to-save-classic-delphi-string-to-disk-and-read-them-back – Gabriel Mar 19 '16 at 14:47
6

The IOUtils unit which was introduced in Delphi 2010 provides some very convenient functions for writing/reading text files:

//add the text 'Some text' to the file 'C:\users\documents\test.txt':
TFile.AppendAllText('C:\users\documents\text.txt', 'Some text', TEncoding.ASCII);
Lars Frische
  • 329
  • 2
  • 4
  • 1
    IOUtils is buggy: http://stackoverflow.com/questions/35708827/what-could-cause-no-mapping-for-the-unicode-character-exists-in-the-target-mult http://stackoverflow.com/questions/35429699/system-ioutils-tdirectory-getparent-odd-behavior – Gabriel Mar 19 '16 at 14:45
4

Or if you are using an older version of Delphi (which does not have the for line in lines method of iterating a string list):

var i : integer;
begin

...
try
    Lines.Add('First line');
    Lines.Add('Second line');
    Lines.SaveToFile(FileName);
    Lines.LoadFromFile(FileName);
    for i := 0 to Lines.Count -1 do
      ShowMessage(Lines[i]);
  finally
    Lines.Free;
  end;
Edelcom
  • 5,038
  • 8
  • 44
  • 61
  • Which should also be a bit more efficient, since `for .. in` does more work in the background. If your Delphi version is new enough and effeciency does not matter I prefer `for .. in` though :) – Jens Mühlenhoff Nov 16 '10 at 16:18
2

If you're using a Delphi version >= 2009, give a look to the TStreamWriter class.

It will also take care of text file encodings and newline characters.

jonsca
  • 10,218
  • 26
  • 54
  • 62
1
procedure String2File;
var s:ansiString;
begin
    s:='My String';
    with TFileStream.create('c:\myfile.txt',fmCreate) do
    try
      writeBuffer(s[1],length(s));
    finally
      free;
    end;
end;

Care needed when using unicode strings....

Vector
  • 10,879
  • 12
  • 61
  • 101