CIniFile - Class for Reading and Writing .INI Files

.

In every program I have written, I end up using some sort of INI file to keep settings from one run to the next. Instead of implementing it separately in each program, I finally got around to writing this class, CIniFile. It is simple to set up and use:

After you create your CIniFile object, call the member function SetPath(CString newpath) to set the path/filename for the ini file to read from and write to.

To read the INI file data into the class, call ReadFile().

To retrieve data from the class, use GetValue or one of its overloads:

//returns value of keyname/valuename as CString
CString GetValue(CString keyname, CString valuename);

//returns value of keyname/valuename as int
int GetValueI(CString keyname, CString valuename);

//returns value of keyname/valuename as double
double GetValueF(CString keyname, CString valuename);

To set data values in the class, call SetValue or one of its overloads:

bool SetValue(CString key,
              CString valuename,
              CString value, bool create = 1);

bool SetValueI(CString key,
               CString valuename,
               int value,
               bool create = 1);

bool SetValueF(CString key,
               CString valuename,
               double value,
               bool create = 1);

Use the optional parameter; create as false if you do not want it to create the key/value if it doesn't already exist.

SetValue returns TRUE if the value was successfully stored, false otherwise.

To delete a value from the class, call DeleteValue(CString keyname, CString valuename). This function will return true if the value is deleted, false otherwise.

To delete an entire key from the class, call DeleteKey(CString keyname). This function will return true if the key is deleted, false otherwise.

To remove all data stored in the class, call Reset().

Other useful functions are GetNumKeys(), which returns the number of keys in the INI file, and GetNumValues(CString keyname), which returns the number of values stored in the specified key.

Finally, to write all your stored data to the specified INI file, call WriteFile().

Thats it! It is simple.

Here is a complete listing of the functions included in the class:

//default constructor
CIniFile();

//constructor, can specify pathname here instead of
//using SetPath later
CIniFile(CString inipath);

//default destructor
virtual ~CIniFile();

//sets path of ini file to read and write from
void SetPath(CString newpath);

//reads ini file specified using CIniFile::SetPath()
//returns true if successful, false otherwise
bool ReadFile();

//writes data stored in class to ini file
void WriteFile();

//deletes all stored ini data
void Reset();

//returns number of keys currently in the ini
int GetNumKeys();

//returns number of values stored for specified key
int GetNumValues(CString keyname);

//gets value of [keyname] valuename =
//overloaded to return CString, int, and double,
//returns, or 0 if key/value not found. Sets error
//member to show problem
CString GetValue(CString keyname, CString valuename);
int GetValueI(CString keyname, CString valuename);
double GetValueF(CString keyname, CString valuename);

//sets value of [keyname] valuename =.
//specify the optional paramter as false (0) if you do not
//want it to create the key if it doesn't exist. Returns true
//if data entered, false otherwise overloaded to accept CString,
//int, and double
bool SetValue(CString key,
              CString valuename,
              CString value,
              bool create = 1);

bool SetValueI(CString key,
               CString valuename,
               int value,
               bool create = 1);

bool SetValueF(CString key,
               CString valuename,
               double value,
               bool create = 1);

//deletes specified value
//returns true if value existed and deleted, false otherwise
bool DeleteValue(CString keyname, CString valuename);

//deletes specified key and all values contained within
//returns true if key existed and deleted, false otherwise
bool DeleteKey(CString keyname);

Downloads

Download demo project and source - 8KB



Comments

  • Works great, except...

    Posted by Legacy on 08/19/2003 12:00am

    Originally posted by: Raymond Lee

    Hi!
    
    

    This is a great piece of code but I stumbled across a slight problem.

    From what I understand, the only time a header is valid is when it's formatted as:

    [MySection]

    Meaning the first character is a "[". My problem was this, I have a kind of list with indexes in the INI file like:

    MyVal[0]=FIRST
    MyVal[1]=SECOND
    etc...

    Because there are "["'s in there the code assumes it's some sort of header. To work around this I've done the following in ReadFile():

    Add a single BOOLean variable: bool parse;

    Now add two small sections of code:

    while( getline( f, line))
    {
    parse = false; // always initialize to false once per loop.

    NEXT:

    if ( (pLeft = line.find_first_of(";#[=")) != string::npos )
    {
    parse = true;

    if ( (pLeft != 0) && (line[pLeft] == '[') )
    {
    if ( (pLeft = line.find_first_of(";#=")) == string::npos )
    parse = false;
    }

    if ( parse == true )
    {
    switch ( line[pLeft])

    The second and third IF statements were added by me, the rest of the code is left as-is. This solves my problems but I haven't done a lot of testing yet to make sure this works in all cases.

    Hope this helps!

    Reply
  • problems with Cyrillic (in VC++7)

    Posted by Legacy on 07/01/2003 12:00am

    Originally posted by: Silent

    Hi!
    Be carefull when using this class in VC++ 70 with localaized INI files.
    This lines of code
    ---------------
    // Check that the user hasn't openned a binary file by checking the first
    // character of each line!
    if ( !isprint( (unsigned char)line[0])) {
    printf( "Failing on char %d\n", line[0]);
    f.close();
    return false;
    }
    ---------------
    prevents CIniFile from reading keynames on chars in range of [129-255] ASCII.
    So I simply removed it assuming user will never open binary file.

    Reply
  • dev://null

    Posted by Legacy on 04/21/2003 12:00am

    Originally posted by: Pavel Selivanov

    Hi.

    I've compared two classes for speed:
    CIniFile(yours) and CDataFile (http://codeguru.earthweb.com/data-misc/CDataFile.html).

    CDataFile is more than 5 times faster on writing !!!!
    Bot of you used an std::vector the same way (almost).

    Is there any reason for this on every new record ??? :
    names.resize( names.size() + 1, keyname);
    keys.resize( keys.size() + 1);
    I think that resize is the reason (moreover, vector can resize himself).

    Why you haven't used an std::map which provides searching of record by name by "Ln N" steps instead of N steps ?

    Reply
  • Performance hits/questions

    Posted by Legacy on 04/21/2003 12:00am

    Originally posted by: Pavel Selivanov

    Hi.

    I've compared two classes for speed:
    CIniFile(yours) and CDataFile (http://codeguru.earthweb.com/data-misc/CDataFile.html).

    CDataFile is more than 5 times faster on writing !!!!
    Bot of you used an std::vector the same way (almost).

    Is there any reason for this on every new record ??? :
    names.resize( names.size() + 1, keyname);
    keys.resize( keys.size() + 1);
    I think that resize is the reason (moreover, vector can resize himself).

    Why you haven't used an std::map which provides searching of record by name by "Ln N" steps instead of N steps ?

    Reply
  • Modifying the GetValue to support Default values

    Posted by Legacy on 11/04/2002 12:00am

    Originally posted by: Gabriel Trzewik

    Support for Default values, as usual in GetPrivateProfileString Windows API
    
    

    In Inifile.h


    //gets value of [keyname] valuename =
    //overloaded to return CString, int, and double,
    //returns "", or 0 if key/value not found or the provided
    //Default value.
    // Sets error member to show problem

    CString GetValue(CString keyname, CString valuename,
    CString Default="");
    int GetValueI(CString keyname, CString valuename,
    int Default=0);
    double GetValueF(CString keyname, CString valuename,
    double Default=0.0);

    In inifile.cpp

    //gets value of [keyname] valuename =
    //overloaded to return CString, int, and double
    CString CIniFile::GetValue(CString keyname, CString valuename, CString Default)
    {
    int keynum = FindKey(keyname), valuenum = FindValue(keynum,valuename);

    if (keynum == -1)
    {
    error = "Unable to locate specified key.";
    return Default;
    }

    if (valuenum == -1)
    {
    error = "Unable to locate specified value.";
    return Default;
    }
    return keys[keynum].values[valuenum];
    }

    //gets value of [keyname] valuename =
    //overloaded to return CString, int, and double
    int CIniFile::GetValueI(CString keyname, CString valuename, int Default)
    {
    int Result;
    error = "";
    Result = atoi(GetValue(keyname,valuename));
    if (error=="")
    return Result;
    else return Default;
    }

    //gets value of [keyname] valuename =
    //overloaded to return CString, int, and double
    double CIniFile::GetValueF(CString keyname, CString valuename, double Default)
    {
    double Result;
    error = "";
    Result = atof(GetValue(keyname, valuename));
    if (error=="")
    return Result;
    else return Default;
    }

    Reply
  • error!!!!!!

    Posted by Legacy on 10/07/2001 12:00am

    Originally posted by: hu

    when you test your project with running it from readonly network sharing folder,it is always fails ""

    Reply
  • Great Article

    Posted by Legacy on 08/23/2001 12:00am

    Originally posted by: Che-lung

    Nice work!!! Superb!!!!
    
    Thanks very much!!!!

    Reply
  • My 2 bits and a correction.

    Posted by Legacy on 08/13/2001 12:00am

    Originally posted by: Darroll Walsh

       First let me start by saying that this is an excellent example of code reuse. I wish I had thought to do this. The only problem I have is that Mr. Clauss states that he uses function overloading when he doesn't. Function overloading, for anyone new to programming, is use the same function name and specify different parameters to be used.
    
    An example:
    SetValue( int x );
    and
    SetValue( float x );
    These are 2 separate functions. What makes them different is the parameters sent to the function. Your compiler determines what function gets called based on the parameters. The advantage of overloading a function is you don't have to remember the function name of how to set an int over a float. You would just call the SetValue(X) function. Mr. Clauss has come close to implementing function overloading. All that would need to be changed is the names of the functions to all SetValue, instead of SetVauleI, and SetValueF.
    I apologize for being picky. I really do admire people who can come up with, implement, and even publish for our use great coding ideas. Thank you Mr. Clauss

    Reply
  • two errors found!

    Posted by Legacy on 04/04/2001 12:00am

    Originally posted by: Joerg

    The first error is in the ReadFile() function. Instead of
    
    using the member function

    file.GetStatus(path,status)

    you have to use the static function

    CFile::GetStatus(path,status)

    Otherwiese the function always fails!

    The second error is that in the article, Adam shows a
    picture where the valuenames (such as "Name = ") looks like
    as they may contain trailing spaces. But then you have to
    look for that value with that space as well, e.g.

    GetValue("[User Info]", "Name "); // note the space !!!

    Third it would be nice to have default values with the
    GetValue() functions to return a default value when the
    value/valuename could not be found.

    Also, the wording is misleading. Instead of talking of
    "keys", "valuenames" and "values" it would be clearer if you
    talk of "sections", "keys" and "values".

    Anyway thanks for the files.

    Joerg

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds