会员: 密码:  免费注册 | 忘记密码 | 会员登录 网页功能: 加入收藏 设为首页 网站搜索  
游戏开发 > 程序设计 > 数据管理
怎样在VC++中读取INI文件
发表日期:2006-08-23 21:00:50作者: 出处:  

 最近有不少朋友写信问我:“如何才能在VC中读取INI文件呢?有没有什么通用的类或者是API?”。实际上这个问题以前也一直困扰着我,我在VC中也找不到这方面的类或API。虽然听说DELPHI里有,但是我又只用VC,没有办法,只好自己动手写了一个专门用来处理INI文件的类——CIni;

  这个类是在去年写的,经过这一年多的实际运用发现效果还算不错,正好最近又有朋友问我这方面的问题,所以我就把它稍微整理了一下,然后作成通用的接口放到网上来给那些需要的朋友们。其实只有两个文件——"Ini.cpp"和"Ini.h",用的时候把这两个文件加入到你自己的工程中,然后在需要读取INI的地方#include "ini.h" 即可使用这个类了,主要有下面4个用法:

  int ReadInt(char* index, char* name);        // 在[index]下面读名为 "name" 的一个整数
  char *ReadText(char* index, char* name);       // 在[index]下面读名为 "name" 的一个字符串
  bool Write(char* index, char* name, int n);    // 在[index]下面写入 "name=n"
  bool Write(char* index, char* name, char *str);  // 在[index]下面写入 "name=str"

  请看下面的例子程序是怎样用的:

 

// 例子
#include "ini.h"

// 保存数据
void Save()
{
    // 打开 test.ini 文件
    CIni Ini("test.ini");

    //[index]下面写入 name=softboy
    Ini.Write("index", "name","softboy");

    //[index]下面写入 年龄=24
    Ini.Write("index", "年龄", 24);

    // 存盘
    Ini.Save();    
    MessageBox("文件 test.ini 保存完毕!");
}

// 读取数据
void Load()
{
    // 打开 test.ini 文件
    CIni Ini("test.ini");

    //[index]下面读取name的值
    char* name = Ini.ReadText("index", "name");

    //[index]下面读取年龄的值
    long age = Ini.ReadInt("index", "年龄");

    // 显示出结果
    char str[64];
    sprintf(str, "name:%s
年龄:%d岁"
, name, age);
    MessageBox(str);

    // 最后不要忘记释放name
    delete( name );
}

 

下面给出ini.cpp和ini.h的完整源程序。

 

//********************************************
//    Ini.h
//********************************************

#ifndef _INI_H_
#define _INI_H_

#ifndef SAFE_DELETE
#define SAFE_DELETE(x)    if( (x)!=NULL ) { delete (x); (x)=NULL; }
#endif

#ifndef SAFE_DELETE_ARRAY
#define SAFE_DELETE_ARRAY(x)    if( (x)!=NULL ) { delete[] (x); (x)=NULL; }
#endif

#ifndef SAFE_FREE
#define SAFE_FREE(x)    if( (x)!=NULL ) { free(x); (x)=NULL; }
#endif

#ifndef SAFE_RELEASE
#define SAFE_RELEASE(x)    if( (x)!=NULL ) { (x)->Release(); (x)=NULL; }
#endif

#define ERROR_DATA -99999999

//配置文件类
class CIni
{
////////////////////////////////////////////////
// 内部数据
////////////////////////////////////////////////
private:
    char m_strFileName[MAX_PATH];    //文件名
    long m_lDataLen;                //文件长度
    char* m_strData;                //文件内容

    int IndexNum;                    //索引数目([]的数目)
    int *IndexList;                    //索引点位置列表
    int Point;                        //当前指针
    int Line, Word;                    //当前行列

////////////////////////////////////////////////
// 通用接口
////////////////////////////////////////////////
public:
    CIni();
    CIni(char*);                            //初始化打开配置文件
    virtual ~CIni();                        //释放内存
    char *GetData();                        //返回文件内容
    int GetLines(int);                        //返回文件的行数

    bool Open(char *);                        //打开配置文件
    void Close();                            //关闭配置文件
    bool Save(char *filename=NULL);            //保存配置文件

////////////////////////////////////////////////
// 内部函数
////////////////////////////////////////////////
private:
    void InitIndex();                        //初始化索引
    int FindIndex(char *);                    //返回标题位置
    int FindData(int, char *);                //返回数据位置
    int GotoNextLine(int);                     //提行
    char *ReadDataName(int &);                //在指定位置读一数据名称
    char *ReadText(int);                    //在指定位置读字符串

    bool AddIndex(char *);                    //加入一个索引
    bool AddData(int, char *, char *);        //在当前位置加入一个数据
    bool ModityData(int, char *, char *);    //在当前位置修改一个数据的值
    int GotoLastLine(char *index);            //把指针移动到本INDEX的最后一行

////////////////////////////////////////////////
// 公用接口
////////////////////////////////////////////////
public:
    int ReadInt(char *, char *);            //读一个整数
    int ReadInt(char *, int );                //在指定的行读一整数
    char *ReadText(char *, char *);            //读一个字符串
    char *ReadText(char *, int);            //在指定的行读一字符串
    char *ReadCaption(char *, int);            //在指定行读一字符名称
    bool Write(char *, char *, int);        //写一个整数
    bool Write(char *, char *, char *);        //写一个字符串
    int GetContinueDataNum(char *);            //返回连续的行数(从INDEX到第一个空行)
};

#endif

 

 

//********************************************
//    Ini.cpp
//********************************************

#include <stdafx.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <io.h>
#include <fcntl.h>
#include <assert.h>
#include "ini.h"

////////////////////////////////////////////////
// 通用接口
////////////////////////////////////////////////

//初始化
CIni::CIni()
{
    m_lDataLen = 0;
    m_strData = NULL;
    IndexNum = 0;
    IndexList = NULL;
}

//初始化
CIni::CIni(char *filename)
{
    m_lDataLen=0;
    m_strData=NULL;
    IndexNum=0;
    IndexList=NULL;
    Open(filename);
}

//析构释放
CIni::~CIni()
{
    if( m_lDataLen != 0 )
    {
        SAFE_DELETE( m_strData );
        m_lDataLen = 0;
    }

    if( IndexNum != 0 )
    {
        SAFE_DELETE( IndexList );
        IndexNum = 0;
    }
}

//读入文件
bool CIni::Open(char *filename)
{
    strcpy(m_strFileName, filename);

    SAFE_FREE( m_strData );

    //获取文件长度
    int fh;
    fh = _open( filename, _O_RDONLY );
    if( fh== -1 )
    {
        m_lDataLen = -1;
    }
    m_lDataLen = _filelength(fh);
    _close(fh);
    
    //文件存在
    if( m_lDataLen > 0 )
    {
        m_strData = new char[m_lDataLen];

        FILE *fp;
        fp=fopen(filename, "rb");
        assert( fp!=NULL );
        fread(m_strData, m_lDataLen, 1, fp);        //读数据
        fclose(fp);

        //初始化索引
        InitIndex();
        return true;
    }
    else    // 文件不存在
    {
        // 找不到文件
        m_lDataLen=1;
        m_strData = new char[m_lDataLen];
        memset(m_strData, 0, 1);
        InitIndex();
    }

    return false;
}

//关闭文件
void CIni::Close()
{
    if( m_lDataLen != 0 )
    {
        SAFE_DELETE( m_strData );
        m_lDataLen = 0;
    }

    if( IndexNum != 0 )
    {
        SAFE_DELETE( IndexList );
        IndexNum = 0;
    }
}

//写入文件
bool CIni::Save(char *filename)
{
    if( filename==NULL )
    {
        filename=m_strFileName;
    }

    FILE *fp;
    fp=fopen(filename, "wb");
    assert( fp!=NULL );

    fwrite(m_strData, m_lDataLen, 1, fp);
    fclose(fp);

    return true;
}

//返回文件内容
char *CIni::GetData()
{
    return m_strData;
}

//获得文件的行数
int CIni::GetLines(int cur)
{
    int n=1;
    for(int i=0; i<cur; i++)
    {
        if( m_strData[i]=='
'
)
            n++;
    }
    return n;
}

////////////////////////////////////////////////
// 内部函数
////////////////////////////////////////////////

//计算出所有的索引位置
void CIni::InitIndex()
{
    IndexNum=0;

    for(int i=0; i<m_lDataLen; i++)
    {
        //找到
        if( m_strData[i]=='[' && ( m_strData[i-1]=='
'
|| i==0 ) )
        {
            IndexNum++;
        }
    }

    //申请内存
    SAFE_DELETE( IndexList );
    if( IndexNum>0 )
        IndexList=new int[IndexNum];

    int n=0;

    for(i=0; i<m_lDataLen; i++)
    {
        if( m_strData[i]=='[' && ( m_strData[i-1]=='
'
|| i==0 ) )
        {
            IndexList[n]=i+1;
            n++;
        }
    }
}

//返回指定标题位置
int CIni::FindIndex(char *string)
{
    for(int i=0; i<IndexNum; i++)
    {
        char *str=ReadText( IndexList[i] );
        if( strcmp(string, str) == 0 )
        {
            SAFE_FREE( str );
            return IndexList[i];
        }
        SAFE_FREE( str );
    }
    return -1;
}

//返回指定数据的位置
int CIni::FindData(int index, char *string)
{
    int p=index;    //指针

    while(1)
    {
        p=GotoNextLine(p);
        char *name=ReadDataName(p);
        if( strcmp(string, name)==0 )
        {
            SAFE_FREE( name );
            return p;
        }

        SAFE_FREE( name );
        if( p>=m_lDataLen ) return -1;
    }
    return -1;
}

//提行
int CIni::GotoNextLine(int p)
{
    for(int i=p; i<m_lDataLen; i++)
    {
        if( m_strData[i]=='
'
)
            return i+1;
    }
    return i;
}

//在指定位置读一数据名称
char *CIni::ReadDataName(int &p)
{
    char chr;
    char *Ret;
    int m=0;

    Ret=new char[64];
    memset(Ret, 0, 64);

    for(int i=p; i<m_lDataLen; i++)
    {
        chr = m_strData[i];

        //结束
        if( chr == '
'
)
        {
            p=i+1;
            return Ret;
        }
        
        //结束
        if( chr == '=' || chr == ';' )
        {
            p=i+1;
            return Ret;
        }
        
        Ret[m]=chr;
        m++;
    }
    return Ret;
}

//在指定位置读一字符串
char *CIni::ReadText(int p)
{
    char chr;
    char *Ret;
    int n=p, m=0;

    int LineNum = GotoNextLine(p) - p + 1;
    Ret=new char[LineNum];
    memset(Ret, 0, LineNum);

    for(int i=0; i<m_lDataLen-p; i++)
    {
        chr = m_strData[n];

        //结束
        if( chr == ';' || chr == '
'
|| chr == '    ' || chr == ']' )
        {
            //ShowMessage(Ret);
            return Ret;
        }
        
        Ret[m]=chr;
        m++;
        n++;
    }

    return Ret;
}

//加入一个索引
bool CIni::AddIndex(char *index)
{
    char str[256];
    memset(str, 0, 256);
    int n=FindIndex(index);

    if( n == -1 )    //新建索引
    {
        sprintf(str,"
[%s]
"
,index);
        m_strData = (char *)realloc(m_strData, m_lDataLen+strlen(str));    //重新分配内存
        sprintf(&m_strData[m_lDataLen], "%s", str);
        m_lDataLen+=strlen(str);

        InitIndex();
        return true;
    }
    
    return false;    //已经存在
}

//在当前位置加入一个数据
bool CIni::AddData(int p, char *name, char *string)
{
    char *str;
    int len=strlen(string);
    str=new char[len+256];
    memset(str, 0, len+256);
    sprintf(str,"%s=%s
"
,name,string);
    len=strlen(str);

    p=GotoNextLine(p);    //提行
    m_strData = (char *)realloc(m_strData, m_lDataLen+len);    //重新分配内存

    char *temp=new char[m_lDataLen-p];
    memcpy(temp, &m_strData[p], m_lDataLen-p);
    memcpy(&m_strData[p+len], temp, m_lDataLen-p);    //把后面的搬到末尾
    memcpy(&m_strData[p], str, len);
    m_lDataLen+=len;

    SAFE_DELETE( temp );
    SAFE_DELETE( str );
    return true;
}

//在当前位置修改一个数据的值
bool CIni::ModityData(int p, char *name, char *string)
{
    int n=FindData(p, name);

    char *t=ReadText(n);
    p=n+strlen(t);
    if( strlen(t)>0 ) free(t);

    int newlen=strlen(string);
    int oldlen=p-n;

    m_strData = (char *)realloc(m_strData, m_lDataLen+newlen-oldlen);    //重新分配内存

    char *temp=new char[m_lDataLen-p];
    memcpy(temp, &m_strData[p], m_lDataLen-p);
    memcpy(&m_strData[n+newlen], temp, m_lDataLen-p);            //把后面的搬到末尾
    memcpy(&m_strData[n], string, newlen);
    m_lDataLen+=newlen-oldlen;

    SAFE_DELETE( temp );
    return true;
}

//把指针移动到本INDEX的最后一行
int CIni::GotoLastLine(char *index)
{
    int n=FindIndex(index);
    n=GotoNextLine(n);
    while(1)
    {
        if( m_strData[n] == '
'
|| m_strData[n] == EOF || m_strData[n] == -3 || m_strData[n] == ' ' || m_strData[n] == '/' || m_strData[n] == '    ' || m_strData[n] == '
'
)
        {
            return n;
        }
        else
        {
            n=GotoNextLine(n);
            if( n >= m_lDataLen ) return n;
        }
    }
}

/////////////////////////////////////////////////////////////////////
// 对外接口
/////////////////////////////////////////////////////////////////////

//以普通方式读一字符串数据
char *CIni::ReadText(char *index, char *name)
{
    int n=FindIndex(index);
    assert( n != -1 );

    int m=FindData(n, name);
    assert( m != -1 );

    return ReadText(m);
}
    
//在指定的行读一字符串
char *CIni::ReadText(char *index, int lines)
{
    int n=FindIndex(index);
    assert( n != -1 );

    //跳到指定行数
    n=GotoNextLine(n);
    for(int i=0; i<lines; i++)
    {
        if( n<m_lDataLen )
            n=GotoNextLine(n);
    }

    //读数据
    while( n<=m_lDataLen )
    {
        if( m_strData[n] == '=' )
        {
            n++;
            return ReadText(n);
        }
        if( m_strData[n] == '
'
)
        {
            return "";
        }
        n++;
    }

    return "";
}

//以普通方式读一整数
int CIni::ReadInt(char *index, char *name)
{
    int n=FindIndex(index);
    assert( n != -1 );

    int m=FindData(n, name);
    assert( m != -1 );

    char *str=ReadText(m);
    int ret=atoi(str);
    free(str);
    return ret;
}

//在指定的行读一整数
int CIni::ReadInt(char *index, int lines)
{
    int n=FindIndex(index);
    assert( n != -1 );

    //跳到指定行数
    n=GotoNextLine(n);
    for(int i=0; i<lines; i++)
    {
        if( n<m_lDataLen )
            n=GotoNextLine(n);
    }

    //读数据
    while( n<m_lDataLen )
    {
        if( m_strData[n] == '=' )
        {
            n++;
            char *str=ReadText(n);
            int ret=atoi(str);
            free(str);
            return ret;
        }
        if( m_strData[n] == '
'
)
        {
            return ERROR_DATA;
        }
        n++;
    }

    return ERROR_DATA;
}

//在指定的行读一数据名称
char *CIni::ReadCaption(char *index, int lines)
{
    int n=FindIndex(index);
    assert( n != -1 );

    //跳到指定行数
    n=GotoNextLine(n);
    for(int i=0; i<lines; i++)
    {
        if( n<m_lDataLen )
            n=GotoNextLine(n);
    }

    return ReadDataName(n);
}

//以普通方式写一字符串数据
bool CIni::Write(char *index, char *name, char *string)
{
    int n=FindIndex(index);
    if( n == -1 )    //新建索引
    {
        AddIndex(index);
        n=FindIndex(index);
        n=GotoLastLine(index);
        AddData(n, name, string);    //在当前位置n加一个数据
        return true;
    }

    //存在索引
    int m=FindData(n, name);
    if( m==-1 )        //新建数据
    {
        n=GotoLastLine(index);
        AddData(n, name, string);    //在当前位置n加一个数据
        return true;
    }

    //存在数据
    ModityData(n, name, string);    //修改一个数据

    return true;
}

//以普通方式写一整数
bool CIni::Write(char *index, char *name, int num)
{
    char string[32];
    sprintf(string, "%d", num);

    int n=FindIndex(index);
    if( n == -1 )    //新建索引
    {
        AddIndex(index);
        n=FindIndex(index);
        n=GotoLastLine(index);
        AddData(n, name, string);    //在当前位置n加一个数据
        return true;
    }

    //存在索引
    int m=FindData(n, name);
    if( m==-1 )        //新建数据
    {
        n=GotoLastLine(index);
        AddData(n, name, string);    //在当前位置n加一个数据
        return true;
    }

    //存在数据
    ModityData(n, name, string);    //修改一个数据

    return true;
}

//返回连续的行数
int CIni::GetContinueDataNum(char *index)
{
    int num=0;
    int n=FindIndex(index);
    n=GotoNextLine(n);
    while(1)
    {
        if( m_strData[n] == '
'
|| m_strData[n] == EOF || m_strData[n] == -3 || m_strData[n] == ' ' || m_strData[n] == '/' || m_strData[n] == '    ' || m_strData[n] == '
'
)
        {
            return num;
        }
        else
        {
            num++;
            n=GotoNextLine(n);
            if( n >= m_lDataLen ) return num;
        }
    }
}

 

  OK,我想这应该是很简单的吧?你只需要知道上面讲的几个重要的接口函数的用法,就可以存取INI文件的内容了!是不是非常的方便:)其实还有几个更为方便的的用法我没有在这里说,不过你只要看一下源程序就应该知道了,而且这个INI类还会不断的扩展,希望大家能和我一起来完善它。

下载:
完整的程序包(含:示例,编译环境VC++6,38K)

返回顶部】 【打印本页】 【关闭窗口

关于我们 / 给我留言 / 版权举报 / 意见建议 / 网站编程QQ群   
Copyright ©2003- 2024 Lihuasoft.net webmaster(at)lihuasoft.net 加载时间 0.00315