To read text files, we advise using the TTextReader class. It provides a line-oriented API, and wraps a TStream inside. The TTextReader constructor can take a ready URL, or you can pass there your custom TStream source.

In the Castle Game Engine : You should use the Download function to create a stream that obtains data from any URL. Regular files, HTTP and HTTPS resources, Android assets and more are supported this way. Moreover, to open the resource inside your game data (in the data subdirectory) use the special castle-data:/xxx URL. Examples:

Modern programs should use TStream class and its many descendants to do input / output. It has many useful descendants, like TFileStream , TMemoryStream , TStringStream .

6.2. Containers (lists, dictionaries) using generics

The language and run-time library offer various flexible containers. There are a number of non-generic classes (like TList and TObjectList from the Contnrs unit), there are also dynamic arrays ( array of TMyType ). But to get the most flexibility and type-safety, I advise using generic containers for most of your needs.

The generic containers give you a lot of helpful methods to add, remove, iterate, search, sort…​ The compiler also knows (and checks) that the container holds only items of the appropriate type.

There are three libraries providing generics containers in FPC now:

FGL unit

Generics.Collections unit and friends

GVector unit and friends (together in fcl-stl )

We advise using the FGL unit (if you need to work with the stable FPC 3.0.x or even older FPC 2.6.x), or the Generics.Collections unit (only available since FPC 3.1.1, but on the other hand compatible with Delphi). They both offer lists and dictionaries with naming consistent with other parts of the standard library (like the non-generic containers from the Contnrs unit).

In the Castle Game Engine: We include a local copy of Generics.Collections even for FPC 3.0.x. We use the Generics.Collections throughout the engine, and advise you to use Generics.Collections too!

Most important classes from the Generics.Collections unit are:

TList A generic list of types. TObjectList A generic list of object instances. It can "own" children, which means that it will free them automatically. TDictionary A generic dictionary. TObjectDictionary A generic dictionary, that can "own" the keys and/or values.

Here’s how to you use a simple generic TObjectList :

{$mode objfpc} {$H+} {$J-} uses SysUtils, Generics.Collections; type TApple = class Name: string ; end ; TAppleList = specialize TObjectList<TApple>; var A: TApple; Apples: TAppleList; begin Apples := TAppleList.Create(true); try A := TApple.Create; A.Name := ' my apple ' ; Apples.Add(A); A := TApple.Create; A.Name := ' another apple ' ; Apples.Add(A); Writeln( ' Count: ' , Apples.Count); Writeln(Apples[ 0 ].Name); Writeln(Apples[ 1 ].Name); finally FreeAndNil(Apples) end ; end .

Note that some operations require comparing two items, like sorting and searching (e.g. by Sort and IndexOf methods). The Generics.Collections containers use for this a comparer. The default comparer is reasonable for all types, even for records (in which case it compares memory contents, which is a reasonable default at least for searching using IndexOf ).

When sorting the list you can provide a custom comparer as a parameter. The comparer is a class implementing the IComparer interface. In practice, you usually define the appropriate callback, and use TComparer<T>.Construct method to wrap this callback into an IComparer instance. An example of doing this is below:

{$mode objfpc} {$H+} {$J-} uses SysUtils, Generics.Defaults, Generics.Collections; type TApple = class Name: string ; end ; TAppleList = specialize TObjectList<TApple>; function CompareApples(constref Left, Right: TApple): Integer; begin Result := AnsiCompareStr(Left.Name, Right.Name); end ; type TAppleComparer = specialize TComparer<TApple>; var A: TApple; L: TAppleList; begin L := TAppleList.Create(true); try A := TApple.Create; A.Name := ' 11 ' ; L.Add(A); A := TApple.Create; A.Name := ' 33 ' ; L.Add(A); A := TApple.Create; A.Name := ' 22 ' ; L.Add(A); L.Sort(TAppleComparer.Construct(@CompareApples)); Writeln( ' Count: ' , L.Count); Writeln(L[ 0 ].Name); Writeln(L[ 1 ].Name); Writeln(L[ 2 ].Name); finally FreeAndNil(L) end ; end .

The TDictionary class implements a dictionary, also known as a map (key → value), also known as an associative array. Its API is a bit similar to the C# TDictionary class. It has useful iterators for keys, values, and pairs of key→value.

An example code using a dictionary:

{$mode objfpc} {$H+} {$J-} uses SysUtils, Generics.Collections; type TApple = class Name: string ; end ; TAppleDictionary = specialize TDictionary< string , TApple>; var Apples: TAppleDictionary; A, FoundA: TApple; ApplePair: TAppleDictionary.TDictionaryPair; AppleKey: string ; begin Apples := TAppleDictionary.Create; try A := TApple.Create; A.Name := ' my apple ' ; Apples.AddOrSetValue( ' apple key 1 ' , A); if Apples.TryGetValue( ' apple key 1 ' , FoundA) then Writeln( ' Found apple under key "apple key 1" with name: ' + FoundA.Name); for AppleKey in Apples.Keys do Writeln( ' Found apple key: ' + AppleKey); for A in Apples.Values do Writeln( ' Found apple value: ' + A.Name); for ApplePair in Apples do Writeln( ' Found apple key->value: ' + ApplePair.Key + ' -> ' + ApplePair.Value.Name); Apples.Remove( ' apple key 1 ' ); A.Free; finally FreeAndNil(Apples) end ; end .

The TObjectDictionary can additionally own the dictionary keys and/or values, which means that they will be automatically freed. Be careful to only own keys and/or values if they are object instances. If you set to "owned" some other type, like an Integer (for example, if your keys are Integer , and you include doOwnsKeys ), you will get a nasty crash when the code executes.

An example code using the TObjectDictionary is below. Compile this example with memory leak detection, like fpc -gl -gh generics_object_dictionary.lpr , to see that everything is freed when program exits.

{$mode objfpc} {$H+} {$J-} uses SysUtils, Generics.Collections; type TApple = class Name: string ; end ; TAppleDictionary = specialize TObjectDictionary< string , TApple>; var Apples: TAppleDictionary; A: TApple; ApplePair: TAppleDictionary.TDictionaryPair; begin Apples := TAppleDictionary.Create([doOwnsValues]); try A := TApple.Create; A.Name := ' my apple ' ; Apples.AddOrSetValue( ' apple key 1 ' , A); for ApplePair in Apples do Writeln( ' Found apple key->value: ' + ApplePair.Key + ' -> ' + ApplePair.Value.Name); Apples.Remove( ' apple key 1 ' ); finally FreeAndNil(Apples) end ; end .

If you prefer using the FGL unit instead of Generics.Collections , here is a short overview of the most important classes from the FGL unit:

TFPGList A generic list of types. TFPGObjectList A generic list of object instances. It can "own" children. TFPGMap A generic dictionary.

In FGL unit, the TFPGList can be only used for types for which the equality operator (=) is defined. For TFPGMap the "greater than" (>) and "less than" (<) operators must be defined for the key type. If you want to use these lists with types that don’t have built-in comparison operators (e.g. with records), you have to overload their operators as shown in the Operator overloading.

In the Castle Game Engine we include a unit CastleGenericLists that adds TGenericStructList and TGenericStructMap classes. They are similar to TFPGList and TFPGMap , but they do not require a definition of the comparison operators for the appropriate type (instead, they compare memory contents, which is often appropriate for records or method pointers). But the CastleGenericLists unit is deprecated since the engine version 6.3, as we advise using Generics.Collections instead.