So-called “INI” files are ubiquitous. You can find them on Unix systems, Windows platforms, and even in the flash memory of embedded systems. I even once wrote my own INI parser for some software on a embedded diskless VME control system running WindRiver’s VxWorks. It allowed us to upload new configuration and control parameters on-the-fly in a human-readable format. Very handy.
Basic INI File Definition
Simply put, an “INI” file contains a list of key:value pairs, usually separated with an equals (“=”) symbol or perhaps a colon. They are also sometimes referred to as KVP files.
Here’s an example from an INI file in my C:\Windows directory:
Name=Times New Roman
and here are a few lines from one of *.conf files on my Linux machine that utilizes colons as separators:
There are other details about INI files as well, such as section headers, comments and so on. Note that not all platforms and library packages support all of the possible variations. To find out more about how Python supports INI files check out this secton of the Python documentation: ConfigParser. Wikipedia also has a nice write-up on the subject, which can be found here: INI file
Using INI Files
Over time I’ve learned that there are some good ways to use INI files and there are some bad ways. Here is a collection of rules and observations that I employ in my work. They are rather Python-centric (since that’s what I’m using a lot these days), but also apply to other languages. You might find them useful as well.
1. Multiple small INI files are better than one big file.
- Small files are easier to manage from within the code. Changing the behavior of a particular sub-system requires only that its (hopefully small) INI be changed, not an entire monster INI file.
- Small files are also easier to document and easier to comprehend, which makes it easier for the user to manually edit them if necessary.
- Small files are less risky to modify from within the code. Small files isolate potential configuration file errors and prevent catastrophic errors from spreading across a large number of parameters. Case in point: When modifying a value in an INI file corrupts everything past the point where the value was modified because there was a system glitch while the file was open for writing.
2. Avoid the Windows Registry (if you can)
Never, ever use the Windows Registry to store configuration data if you think there’s even the teeniest chance that the code will ever get ported to a different platform someday. If there’s even a shred of doubt, then use text-based INI type files instead. This will help to insure easier portability across multiple platforms. The Windows Registry is also notorious for having various problems of its own, and is a gateway into the system for malicious code. I realize that this is in direct opposition to Microsoft’s desire that the old INI files just go away, but until they can figure out how to write an OS that doesn’t trip over itself, has configuration data that is easy to read, edit and transport, and doesn’t leave the back door open to malicious code I’m going to have to refuse to take the “registry only” route. Oh, and did I mention that it makes code non-portable?
3. Use Simple Strings for Keys and Values
If a value cannot be represented easily as a simple string, then it probably doesn’t belong in an INI file. In other words, if the code can’t figure out if the value part of the KV pair is supposed to be a single integer, float, long, string, or in Python, a tuple, list or dictionary object, then it should probably be in a custom format data file. Python provides the pickling mechanism for serializing objects, and there are other options (such as the PGM binary image data format) available.
4. Pairing Related Data
When a parameter requires additional information, like for example the units of measurement, then use a Python tuple or store the units value as a separate parameters in the INI file. For example:
As a tuple in Python:
output_lambda: (687, nm)
Or as seperate parameters:
Do not store the value as:
output_lambda: 687 nm
A Python utility such as the autoconvertor I presented earlier (see this page: Automagical Configuration Data Conversion In Python) can easily handle all of the standard Python types, but it won’t handle something like “687 nm”. For that you’ll need to write your own custom parser, and personally I’d rather spend my time doing something else. Using separate parameters for values and units can make things easier to process in any language.
5. Don’t Overload the INI File
Store data that is more properly represented in binary in a binary file. In other words, it’s not a good idea to convert a 2D image (even a really small one) into a 2D array of values in ASCII just so it can be stored in an INI file. Don’t snicker, I’ve seen this done.
Although often treated as an afterthought, or created ad hoc as the code is hacked into existence, an application’s configuration parameters play in big role in how well it can be tested, tuned and maintained. Overly large INI files can make life difficult when it doesn’t need to be, and can lead to crashes or strange behaviors. Take a moment and plan how INI files will utilized up-front: set some initial guidelines for size, context and content type, and then stick to them. You’ll be glad you did.