Writing large INI files

INI files, once the most used way for storing program configurations, are still popular due to their simplicity. Delphi offers two ways for accessing them:

If you only want to read or write a few values, it’s fine to use TIniFile. The underlying Windows API functions have a size limit of 64 KB though, which you might or might not reach. Once you reach it, you will experience very odd behaviour. I could not find any official documentation on whether this limit has been lifted in recent versions of Windows.

TMemIniFile does not suffer from that restriction, but it has its own: First, it might have worse performance if you only read or write a few values, because it reads the full file into memory. It also ignores any comments marked by ‘;’, so writing the file back will remove these comments. (You can still use a different comment marker e.g. // or # though.) And don’t forget to call UpdateFile if you changed it! Otherwise your changes are lost.

For writing large INI files, don’t even consider using TIniFile. It takes forever! But what about TMemIniFile? It’s much faster, but is it as fast as possible? No, it’s not. Here are two methods for writing an INI file that are even faster:

  • TStringList – but only if you recreate the full file anyway and the entries are simple
  • TFastIniFile – if you want to use a 3rd party library

The GExperts Class Browser expert writes .gex files which are INI files with a different extension to store the class list it retrieved from source files. These .gex files can be large e.g. if you add the VCL directory of Delphi 2007 the resulting file is 68 KB and contains 617 entries. The class browser used to use TIniFile to read and write these files. Here are my timing results:

Writing with TIniFile took 2,368 s
Writing with TMemIniFile took 0,236 s
Writing with TMemIniFile.SetStrings took 0,005 s
Writing with TStringList.SaveToFile took 0,004 s

So, there is a factor of 10 between TMemIniFile and TIniFile and a factor of *drumroll* 50 between TStringList and and TMemIniFile. Changing the code from TIniFile to TStringList sped up that code by a factor of whooping 500! And since these files tend to get large that’s significant.

But what if you don’t rewrite the whole file? If you just want to, say, add a new section with 100 entries to it? Yes, you could still use TStringList but that would be rather inconvenient. INI files are mostly about convenience. So I looked for a faster implementation and found TFastIniFile by Pieter Zijlstra. According to Pieter it has been updated to Delphi XE4. I tested it with Delphi 2007 and the results are impressive. It’s nearly as fast as using a TStringList and has a few features that TMemIniFile has not: It preserves comments and blank lines. It supports inline comments. Here is the result of the speed benchmark from the demo program he supplies:

(Re)write 400 sections each with 10 ident=value’s
TIniFile 25,333 s 87224 Kb
TMemIniFile 0,037 s 88504 Kb
TFastIniFile ANSI 0,008 s 88504 Kb
TFastIniFile 0,010 s 88504 Kb

I didn’t use it in GExperts because it was not necessary but it might be well worth checking out if your program routinely works with large INI files.

My thanks to Daniela Osterhagen for reminding me that writing an INI file can easily be done with a TStringList.