wince 读写 ini 文件 操作 MFC

 我这篇也是借鉴别人的,分为 inifile.h   inifile.cpp  和应用部分

 

1. inifile.h  源码

#ifndef INIFILE_H
#define INIFILE_H

//是否在WINCE平台上
#ifndef WINCE
#define WINCE
#endif

#include "StdAfx.h"
#ifndef WINCE
#include <io.h>        //for _sopen
#include <fcntl.h>    //for _O_RDWT
#include <share.h>    // for _SH_DENYRW
#endif

#ifdef  UNICODE   // r_winnt
#define t_sopen            _wsopen        //注意WinCe上不支持!
#define t_fopen         _wfopen
#define t_fgets            fgetws
#define t_fprintf        fwprintf    //文件格式化写入
#define t_sprintf        swprintf    //格式化文本
#define t_strcpy        wcscpy
#define t_strncpy        wcsncpy        //拷贝指定个数的字符
#define t_strcat        wcscat        //append a string
#define t_strtol        wcstol
#define t_strlen        wcslen
#define t_strcmp        wcscmp
#define t_stricmp        _wcsicmp    //忽略大小写的字符串比较
#define t_strncmp        wcsncmp        //比较n个字符
#define t_strchr        wcschr        //find a character in a string
#define t_strrchr        wcsrchr        //从结尾向前查找字符

#else  //ASCII CODE

#define t_sopen            _sopen        //注意WinCe上不支持!
#define t_fopen         fopen
#define t_fgets            fgets        //读取一行文本
#define t_fprintf        fprintf        //文件格式化写入
#define t_sprintf        sprintf        //格式化文本
#define t_strcpy        strcpy
#define t_strncpy        strncpy        //拷贝指定个数的字符
#define t_strcat        strcat        //append a string
#define t_strtol        strtol        //把字符串转换成long(int32)
#define t_strlen        strlen
#define t_strcmp        strcmp        //比较字符串
#define t_stricmp        _stricmp    //忽略大小写的字符串比较
#define t_strncmp        strncmp        //比较n个字符
#define t_strchr        strchr        //查找字符
#define t_strrchr        strrchr        //从结尾向前查找字符

#endif

//CeWritePrivateProfileString 方法用到的辅助标记
#define MODE_DELETE_SECTION        11
#define MODE_OVERWRITE_SECTION    12
#define MODE_APPEND_SECTION        13
#define MODE_DELETE_KEY            21
#define MODE_OVERWRITE_KEY        22
#define MODE_APPEND_KEY            23

#define LINESIZE                260    //行缓冲区大小

DWORD CeGetPrivateProfileString(
        LPCTSTR lpAppName,                //section name: [lpAppName]
        LPCTSTR lpKeyName,                //lpKeyName=lpReturnedString
        LPCTSTR lpDefault,                //未找到时的默认值
        LPTSTR lpReturnedString,        //[out] 查找到的结果
        DWORD nSize,                    //[in]lpReturnedString的字符数,注意单位不是字节!
        LPCTSTR lpFileName
        );

UINT CeGetPrivateProfileInt(
       LPCTSTR lpAppName,
       LPCTSTR lpKeyName,
       int nDefault,
       LPCTSTR lpFileName
       );

DWORD CeGetPrivateProfileSection(
         LPCTSTR lpAppName,
         LPTSTR lpReturnedString,
         DWORD nSize,
         LPCTSTR lpFileName
         );

DWORD CeGetPrivateProfileSectionNames(
           LPTSTR lpszReturnBuffer,
           DWORD nSize,
           LPCTSTR lpFileName
           );

//在PC平台上可以调用_chsize函数调整文件大小,但是在WINCE平台上
//由于不支持,所以必须注意当文件尺寸应该缩小时,文件尾部内容不确定!!!!
BOOL CeWritePrivateProfileString(
         LPCTSTR lpAppName,
         LPCTSTR lpKeyName,    //要修改的KEY,如果为NULL,会删除整个Section
         LPCTSTR lpString,    //要写入的值,如果为NULL,则会删除这个KEY
         LPCTSTR lpFileName
         );

//重写某个Section,注意和 PC API 的区别是,这里不保证原子性操作
BOOL CeWritePrivateProfileSection(
          LPCTSTR lpAppName,    //section name
          LPCTSTR lpString,    //key1=val1 \0 key2=val2 \0\0
          LPCTSTR lpFileName
          );

//==============================================
//        以下是我增加的函数(在API中没有)
//==============================================
DWORD CeGetPrivateProfileKeyNames(
          LPCTSTR lpAppName,
          LPTSTR lpReturnedString,
          DWORD nSize,                //缓冲区的字符数
          LPCTSTR lpFileName
          );

#endif

 

 

2.inifile.cpp 源码

 

//适用于 char* 和 UNICODE,
//所有字符串必须使用 TEXT("aa") 或者 _T("aa") 的格式(自动适应 char* 或 UNICODE)
//所有相关函数加t_前缀
//IniFile: 读取INI FILE的简单解析!所谓简单,也就是解析代码简单,但对文件格式要求更高
//[1]任何字符串前后不要有空格(使解析代码可以不考虑前后的trim)
//            例如允许"Key1=Val", 而不允许" Key1 = Val "
//[2]允许有注释,第一个字符必须是英文分号';'
//
#include "StdAfx.h"
#include "IniFile.h"

//从appname(section)中读取string类型key
DWORD CeGetPrivateProfileString(
        LPCTSTR lpAppName,                //section name: [lpAppName]
        LPCTSTR lpKeyName,                //lpKeyName=lpReturnedString
        LPCTSTR lpDefault,                //未找到时的默认值
        LPTSTR lpReturnedString,    //[out] 查找到的结果
        DWORD nSize,                            //[in]lpReturnedString的字符数,注意单位不是字节!
        LPCTSTR lpFileName
        )
{
 DWORD ret = 0;
 FILE *stream;
 bool bFindVal = false;
 bool bFindSection = false;
 TCHAR line[ LINESIZE ];
 size_t sectionLength, keyLength, lineLength;

 stream = t_fopen(lpFileName, _T("r"));
 if(stream == NULL)
 {
  //设置默认值
  t_strcpy(lpReturnedString, lpDefault);
  ret = t_strlen(lpReturnedString);
  return ret;
 }

 sectionLength = t_strlen(lpAppName);

 while(t_fgets(line, LINESIZE, stream) != NULL)
 {
  //忽略注释行和空行
  if(line[0] == 0 || line[0] == ';') continue;
  lineLength = t_strlen(line);
  //注意:把LF(0xa)字符替换成0,这在UNICODE环境下可能出现结尾是LF)
  if(line[ lineLength - 1 ] == 0x0a)
  {
   line[ lineLength - 1 ] = 0;
   lineLength--;
   //注意此时可能会成为空字符串
   if(lineLength == 0) continue;
  }

  //尝试寻找到 section
  if(!bFindSection)
  {
   if(line[0] != '[') continue; //本行是否是 [section]
   //这里是我们想要的Section吗?
   //检查这一行的宽度是否正好是section长度加2, [lpAppName]
   if(line[sectionLength + 1] != ']') continue;
   if(t_strncmp(line+1, lpAppName, sectionLength) != 0) continue;
   //Now Section will appear on next line
   //读取section前求出 Key 的长度
   keyLength = t_strlen(lpKeyName);
   bFindSection = true;           
   continue;
  }

  //查找Key, Section End?
  if(line[0]=='[') break; //遇到了下一个

  if(lineLength < keyLength+1 || line[keyLength] != '=') continue; //"KeyName="
  if(t_strncmp(line, lpKeyName, keyLength)!=0) continue;
  //Now We Get the Key!
  t_strcpy(lpReturnedString, line + keyLength + 1);
  //Now It's done.
  bFindVal = true;
  break;
 }

 fclose(stream);
 if(!bFindVal)
 {
  //设置默认值
  t_strcpy(lpReturnedString, lpDefault);
 }
 ret = t_strlen(lpReturnedString);
 return ret;
}


//读取一个int值
UINT CeGetPrivateProfileInt(
       LPCTSTR lpAppName,
       LPCTSTR lpKeyName,
       int nDefault,
       LPCTSTR lpFileName
       )
{
 long ret = nDefault; //返回值
 FILE *stream;
 bool bFindVal = false;
 bool bFindSection = false;
 TCHAR line[ LINESIZE ];
 size_t sectionLength, keyLength, lineLength;

 stream = t_fopen(lpFileName, _T("r"));
 if(stream == NULL)
 {
  //设置默认值
  return nDefault;
 }

 sectionLength = t_strlen(lpAppName);

 while(t_fgets(line, LINESIZE, stream) != NULL)
 {
  //忽略注释行和空行
  if(line[0] == 0 || line[0] == ';') continue;
  lineLength = t_strlen(line);
  //注意:把LF(0xa)字符替换成0,这在UNICODE环境下可能出现结尾是LF)
  if(line[ lineLength - 1 ] == 0x0a)
  {
   line[ lineLength - 1 ] = 0;
   lineLength--;
   //注意此时可能会成为空字符串
   if(lineLength == 0) continue;
  }

  //尝试寻找到 section
  if(!bFindSection)
  {
   if(line[0] != '[') continue; //本行是否是 [section]
   //这里是我们想要的Section吗?
   //检查这一行的宽度是否正好是section长度加2, [lpAppName]
   if(line[sectionLength + 1] != ']') continue;
   if(t_strncmp(line+1, lpAppName, sectionLength) != 0) continue;
   //Now Section will appear on next line
   //读取section前求出 Key 的长度
   keyLength = t_strlen(lpKeyName);
   bFindSection = true;           
   continue;
  }

  //查找Key, Section End?
  if(line[0]=='[') break; //遇到了下一个

  if(lineLength < keyLength+1 || line[keyLength] != '=') continue; //"KeyName="
  if(t_strncmp(line, lpKeyName, keyLength)!=0) continue;
  //Now We Get the Key!
  TCHAR *pStopChar = NULL;
  ret = t_strtol(line + keyLength + 1, &pStopChar, 10); //默认为10进制
  //Now It's done.
  bFindVal = true;
  break;
 }

 fclose(stream);
 return ret;
}


//获取某个Section下面的所有“key=value”形式的字符串集合,以0字符分割
//结尾使用两个0字符
//缓冲区写入:"key1=value1 \0 key2=value2 \0 \0 "
//返回值表示写入缓冲区的字符数, 不包括结尾的0字符。
//如果缓冲区不够容纳所有的键值对,则返回值 = (nSize-2)
DWORD CeGetPrivateProfileSection(
         LPCTSTR lpAppName,
         LPTSTR lpReturnedString,
         DWORD nSize,                //缓冲区的字符数
         LPCTSTR lpFileName
         )
{
 DWORD ret = 0; //返回值,拷贝的字符数量
 DWORD remainSize = nSize - 2; //缓冲区当前所能能够接纳的字符数量
 DWORD copySize;                //本次循环中需要拷贝的字符数量
 FILE *stream;
 bool bFindSection = false; //是否已经找到Section
 TCHAR line[ LINESIZE ];   //行缓冲区
 LPTSTR pItem; //指向当前键值对的写入地址
 size_t sectionLength, lineLength;


 pItem = lpReturnedString; //指向缓冲区起始地址

 stream = t_fopen(lpFileName, _T("r"));
 if(stream == NULL)
 {
  return ret;
 }

 sectionLength = t_strlen(lpAppName);

 while(t_fgets(line, LINESIZE, stream) != NULL)
 {
  //缓冲区是否还有剩余空间?
  if(remainSize <= 0) break;

  //忽略注释行和空行
  if(line[0] == 0 || line[0] == ';') continue;
  lineLength = t_strlen(line);
  //注意:把LF(0xa)字符替换成0,这在UNICODE环境下可能出现结尾是LF)
  if(line[ lineLength - 1 ] == 0x0a)
  {
   line[ lineLength - 1 ] = 0;
   lineLength--;
   //注意此时可能会成为空字符串
   if(lineLength == 0) continue;
  }

  //尝试寻找到 section
  if(!bFindSection)
  {
   if(line[0] != '[') continue; //本行是否是 [section]
   //这里是我们想要的Section吗?
   //检查这一行的宽度是否正好是section长度加2, [lpAppName]
   if(line[sectionLength + 1] != ']') continue;
   if(t_strncmp(line+1, lpAppName, sectionLength) != 0) continue;
   //Now Section will appear on next line
   bFindSection = true;           
   continue;
  }

  //查找Key, Section End?
  if(line[0]=='[') break; //遇到了下一个

  //copy the line to buffer, 注意ncpy不会复制结尾的0字符
  copySize = min( remainSize, lineLength );
  t_strncpy(pItem, line, copySize);
  //追加一个0字符
  pItem[copySize] = 0;

  //缩小缓冲区剩余字符数量remainSize,和当前写入位置pItem
  ret += (copySize + 1); //加1是为了统计结尾的0字符
  remainSize -= (copySize + 1);
  pItem += (copySize + 1);
 }

 fclose(stream);

 if(bFindSection)
 {
  //再次对缓冲区追加一个0 字符
  *pItem = 0;
 }
 return ret;
}


//获取一个ini文件中所有section的name,拷贝到缓冲区
//注意和系统API的区别是,系统API的读取是原子性的,即读取时不允许修改ini文件的内容
//而我们的函数未必保证这一点
DWORD CeGetPrivateProfileSectionNames(
           LPTSTR lpszReturnBuffer,
           DWORD nSize,
           LPCTSTR lpFileName
           )
{
 DWORD ret = 0;                    //返回值,拷贝的字符数量
 DWORD remainSize = nSize - 2;    //缓冲区当前所能能够接纳的字符数量
 DWORD copySize;                    //本次循环中需要拷贝的字符数量
 TCHAR line[ LINESIZE ];            //行缓冲区
 TCHAR *pSectionEndChar;            //']'字符指针
 LPTSTR pItem;                    //指向当前键值对的写入地址
 FILE *stream;                    //流指针
 size_t lineLength;                //行字符长度

 pItem = lpszReturnBuffer; //指向缓冲区起始地址

 stream = t_fopen(lpFileName, _T("r"));
 if(stream == NULL)
 {
  return ret;
 }

 while(t_fgets(line, LINESIZE, stream) != NULL)
 {
  //缓冲区是否还有剩余空间?
  if(remainSize <= 0) break;

  //忽略注释行和空行
  if(line[0] == 0 || line[0] == ';') continue;
  lineLength = t_strlen(line);
  //注意:把LF(0xa)字符替换成0,这在 UNICODE 环境下可能出现结尾是LF)
  if(line[ lineLength - 1 ] == 0x0a)
  {
   line[ lineLength - 1 ] = 0;
   lineLength--;
   //注意此时可能会成为空字符串
   if(lineLength == 0) continue;
  }

  if(line[0] != '[') continue; //本行是否是 [section]
  //找到了一个Section,开始拷贝
  //copy the section name to buffer, 注意ncpy不会复制结尾的0字符

  //LINE: "[sectionName]"
  //       |           |
  //     line      pSectionEndChar

  //找出‘=’字符的位置
  pSectionEndChar = t_strchr(line, ']');
  if(pSectionEndChar != NULL)
  {
   //找到了‘=’字符,(pEqualChar - line)是key的长度
   copySize = min( remainSize,  pSectionEndChar - line - 1 );
  }
  else
  {
   //本行中不存在‘]’字符,对于合法文件来说不会出现此种情况
   copySize = min( remainSize, lineLength - 1 );
  }

  t_strncpy(pItem, line+1, copySize);

  //追加一个0字符
  pItem[copySize] = 0;

  //缩小缓冲区剩余字符数量remainSize,和当前写入位置pItem
  ret += (copySize + 1); //加1是为了统计结尾的0字符
  remainSize -= (copySize + 1);
  pItem += (copySize + 1);
 }

 fclose(stream);
 //再次对缓冲区追加一个0 字符
 *pItem = 0;
 return ret;
}

//
BOOL CeWritePrivateProfileString(
         LPCTSTR lpAppName,
         LPCTSTR lpKeyName,    //要修改的KEY,如果为NULL,会删除整个Section
         LPCTSTR lpString,    //要写入的值,如果为NULL,则会删除这个KEY
         LPCTSTR lpFileName
         )
{
 FILE *stream;
 void *pVoid = NULL; //文件的后半部分
 bool bFindKey = false;
 bool bFindSection = false;
 TCHAR line[ LINESIZE ];
 size_t sectionLength, keyLength, lineLength, nBytesRead = 0;
 LONG nInsertPos = -1, nCopyPos = -1, nFileEndPos, nPos; //文件指针位置
 LONG nSectionBegin = -1, nKeyBegin = -1, nNextKey = -1, nNextSection = -1;
 BYTE mode = 0;

 //如果 sectionName 为NULL,返回成功
 if(lpAppName == NULL)
  return true;

 //r+: Opens for both reading and writing. (The file must exist.)
 stream = t_fopen(lpFileName, _T("r+"));
 if(stream == NULL)
 {
  return false;
 }

 //先取一次mode的默认值
 if(lpKeyName == NULL)
  mode = MODE_DELETE_SECTION;
 else if(lpString == NULL)
  mode = MODE_DELETE_KEY;
 else
  mode = MODE_OVERWRITE_KEY;

 sectionLength = t_strlen(lpAppName);

 //每次读行前,保存文件指针位置
 while(nPos = ftell(stream), t_fgets(line, LINESIZE, stream) != NULL)
 {
  //忽略注释行和空行
  if(line[0] == 0 || line[0] == ';') continue;
  lineLength = t_strlen(line);
  //注意:把LF(0xa)字符替换成0,这在UNICODE环境下可能出现结尾是LF)
  if(line[ lineLength - 1 ] == 0x0a)
  {
   line[ lineLength - 1 ] = 0;
   lineLength--;
   //注意此时可能会成为空字符串
   if(lineLength == 0) continue;
  }

  //尝试寻找到 section
  if(!bFindSection)
  {
   if(line[0] != '[') continue; //本行是否是 [section]
   //这里是我们想要的Section吗?
   //检查这一行的宽度是否正好是section长度加2, [lpAppName]
   if(line[sectionLength + 1] != ']') continue;
   if(t_strncmp(line+1, lpAppName, sectionLength) != 0) continue;
   //Now Section will appear on next line
   //读取section前求出 Key 的长度
   if(lpKeyName != NULL)
    keyLength = t_strlen(lpKeyName);

   nSectionBegin = nPos;

   bFindSection = true;       
   continue;
  }

  //Section找到了,
  //Section End ?
  if(line[0]=='[')
  {
   nNextSection = nPos;
   break; //遇到了下一个
  }

  //是否需要查找KEY?
  if(lpKeyName != NULL)
  {           
   if(lineLength < keyLength+1 || line[keyLength] != '=') continue; //"KeyName="
   if(t_strncmp(line, lpKeyName, keyLength) != 0) continue;
   //Now We Get the Key!
   nKeyBegin = nPos;
   nNextKey = ftell(stream); //要拷贝的起始位置
   //Now It's done.
   bFindKey = true;
   break;
  }
 }

 //如果已经到达文件尾部,则追加换行
 if(feof(stream))
  t_fprintf(stream, _T("\r\n"));

 if(nNextSection < 0) nNextSection = ftell(stream);
 if(nNextKey < 0) nNextKey = ftell(stream);

 //遍历后再次更新mode值
 if(mode == MODE_DELETE_SECTION)
 {
  if(!bFindSection)
  {
   fclose(stream);
   return true;
  }
  else
  {
   nInsertPos = nSectionBegin;
   nCopyPos = nNextSection;
  }
 }
 if(mode == MODE_DELETE_KEY)
 {
  if(!bFindKey)
  {
   fclose(stream);
   return true;
  }
  else
  {
   nInsertPos = nKeyBegin;
   nCopyPos = nNextKey;
  }
 }
 if(mode == MODE_OVERWRITE_KEY)
 {
  if(!bFindSection)
  {
   mode = MODE_APPEND_SECTION;
  }
  else
  {
   if(bFindKey)
   {
    nInsertPos = nKeyBegin;
    nCopyPos = nNextKey;
   }
   else
   {
    mode = MODE_APPEND_KEY;
    nInsertPos = nNextSection;
    nCopyPos = nNextSection;
   }
  }
 }

 //追加一个新的Section
 if(mode == MODE_APPEND_SECTION)
 {
  t_fprintf(stream, _T("\r\n[%s]\r\n%s=%s\r\n"), lpAppName, lpKeyName, lpString);
  fclose(stream);
  return true;
 }

 //先把文件的后半部分拷贝到内存
 fseek(stream, 0, SEEK_END);
 nFileEndPos = ftell(stream);
 if(nCopyPos >= 0 && nCopyPos < nFileEndPos)
 {
  //分配内存作为缓冲区
  pVoid = malloc(nFileEndPos - nCopyPos + 1);

  if(pVoid == NULL)
  {
   fclose(stream);
   return false; //堆内存不足
  }
  fseek(stream, nCopyPos, SEEK_SET);
  nBytesRead = fread(pVoid, 1, nFileEndPos - nCopyPos + 1, stream);
 }

 //写入新的value值
 fseek(stream, nInsertPos, SEEK_SET);
 if(lpKeyName != NULL && lpString != NULL)
  t_fprintf(stream, _T("%s=%s\r\n"), lpKeyName, lpString);

 //现在把文件的后半部分写回文件中
 if(pVoid != NULL && nBytesRead > 0)
 {
  fwrite(pVoid, 1, nBytesRead, stream);
  free(pVoid);
 }

 //此时结尾可能还有一些内容,属于原来的ini文件
 //我们把它写成注释
 nPos = ftell(stream);
 fclose(stream);

 //如果文件变小了,那么我们需要更改文件大小
 if(nPos < nFileEndPos)
 {
#ifdef WINCE    //WINCE平台
  HANDLE handle = CreateFile(
   lpFileName, //LPCTSTR lpFileName
   GENERIC_WRITE, //DOWRD dwDesiredAccess,
   0, //DWORD dwShareMode, 非共享模式
   NULL, //LPSECURITY_ATTRIBUTES lpSecurityAttributes, ignored
   OPEN_EXISTING, //DWORD dwCreationDispostion,
   FILE_ATTRIBUTE_NORMAL, //DWORD dwFlagsAndAttributes,
   NULL//HANDLE hTemplateFile, ignored
   );

  if(handle != NULL)
  {
   //移动文件指针
   SetFilePointer(handle, nPos, NULL, FILE_BEGIN);
   //设置EOF
   SetEndOfFile(handle);
   //关闭
   CloseHandle(handle);
  }

#else            //PC 平台
  int handle = t_sopen(lpFileName, _O_RDWR, _SH_DENYRW);
  if(handle > 0)
  {
   //修改文件大小
   _chsize(handle, nPos);
   //关闭文件
   _close(handle);
  }
#endif //
 }
 return TRUE;
}


//重写某个Section,注意和 PC API 的区别是,这里不保证原子性操作
BOOL CeWritePrivateProfileSection(
          LPCTSTR lpAppName,    //section name
          LPCTSTR lpString,    //key1=val1 \0 key2=val2 \0\0
          LPCTSTR lpFileName
          )
{
 FILE *stream;
 void *pVoid = NULL; //文件的后半部分
 bool bFindSection = false;
 TCHAR line[ LINESIZE ]; //行缓冲区
 LPCTSTR pItem = lpString;
 size_t sectionLength, lineLength, nBytesRead = 0;
 LONG nFileEndPos, nPos; //文件指针位置
 LONG nSectionBegin = -1, nNextSection = -1;

 //如果 sectionName 为NULL,返回失败
 if(lpAppName == NULL || lpString == NULL)
  return false;

 //r+: Opens for both reading and writing. (The file must exist.)
 stream = t_fopen(lpFileName, _T("r+"));
 if(stream == NULL)
 {
  return false;
 }

 sectionLength = t_strlen(lpAppName);

 //每次读行前,保存文件指针位置
 while(nPos = ftell(stream), t_fgets(line, LINESIZE, stream) != NULL)
 {
  //忽略注释行和空行
  if(line[0] == 0 || line[0] == ';') continue;
  lineLength = t_strlen(line);
  //注意:把LF(0xa)字符替换成0,这在UNICODE环境下可能出现结尾是LF)
  if(line[ lineLength - 1 ] == 0x0a)
  {
   line[ lineLength - 1 ] = 0;
   lineLength--;
   //注意此时可能会成为空字符串
   if(lineLength == 0) continue;
  }

  //尝试寻找到 section
  if(!bFindSection)
  {
   if(line[0] != '[') continue; //本行是否是 [section]
   //这里是我们想要的Section吗?
   //检查这一行的宽度是否正好是section长度加2, [lpAppName]
   if(line[sectionLength + 1] != ']') continue;
   if(t_strncmp(line+1, lpAppName, sectionLength) != 0) continue;
   //Now Section will appear on next line
   nSectionBegin = nPos;
   bFindSection = true;       
   continue;
  }

  //Section找到了,
  //Section End ?
  if(line[0]=='[')
  {
   nNextSection = nPos;
   break; //遇到了下一个
  }
 }

 //如果已经到达文件尾部,则追加换行
 if(nNextSection < 0) nNextSection = ftell(stream);

 //追加一个新的Section
 if(!bFindSection)
 {
  nSectionBegin = ftell(stream);
 }

 //覆写Section
 //先把文件的后半部分拷贝到内存
 fseek(stream, 0, SEEK_END);
 nFileEndPos = ftell(stream);
 if(nNextSection >= 0 && nNextSection < nFileEndPos)
 {
  //分配内存作为缓冲区
  pVoid = malloc(nFileEndPos - nNextSection + 1);

  if(pVoid == NULL)
  {
   fclose(stream);
   return false; //堆内存不足
  }
  fseek(stream, nNextSection, SEEK_SET);
  nBytesRead = fread(pVoid, 1, nFileEndPos - nNextSection + 1, stream);
 }

 //逐行写入key = val
 fseek(stream, nSectionBegin, SEEK_SET);
 //再次写入[section],如果不存在就会追加
 t_fprintf(stream, _T("[%s]\r\n"), lpAppName);
 while(*pItem)
 {
  t_fprintf(stream, _T("%s\r\n"), pItem);
  pItem += t_strlen(pItem) + 1; //移动到下一行
 }

 //现在把文件的后半部分写回文件中
 if(pVoid != NULL)
 {
  fwrite(pVoid, 1, nBytesRead, stream);
  free(pVoid);
 }

 //此时结尾可能还有一些内容,属于原来的ini文件
 //我们把它写成注释
 nPos = ftell(stream); //当前文件位置
 fclose(stream);

 //如果文件变小了,那么我们需要更改文件大小
 if(nPos < nFileEndPos)
 {
#ifdef WINCE    //WINCE平台
  HANDLE handle = CreateFile(
   lpFileName, //LPCTSTR lpFileName
   GENERIC_WRITE, //DOWRD dwDesiredAccess,
   0, //DWORD dwShareMode, 非共享模式
   NULL, //LPSECURITY_ATTRIBUTES lpSecurityAttributes, ignored
   OPEN_EXISTING, //DWORD dwCreationDispostion,
   FILE_ATTRIBUTE_NORMAL, //DWORD dwFlagsAndAttributes,
   NULL//HANDLE hTemplateFile, ignored
   );

  if(handle != NULL)
  {
   //移动文件指针
   SetFilePointer(handle, nPos, NULL, FILE_BEGIN);
   //设置EOF
   SetEndOfFile(handle);
   //关闭
   CloseHandle(handle);
  }

#else            //PC 平台
  int handle = t_sopen(lpFileName, _O_RDWR, _SH_DENYRW);
  if(handle > 0)
  {
   //修改文件大小
   _chsize(handle, nPos);
   //关闭文件
   _close(handle);
  }
#endif //
 }
 return TRUE;
}


//===========================================================
//        以下是我增加的函数(API中没有)
//===========================================================

//
//获取某个section下的所有的Key名,
//获取某个Section下面的所有“key形式的字符串集合,以0字符分割
//结尾使用两个0字符
//缓冲区写入:"key1 \0 key2 \0 \0 "
//返回值表示写入缓冲区的字符数, 不包括结尾的0字符。
//如果缓冲区不够容纳所有的键值对,则返回值 = (nSize-2)

//注意:此函数是在桌面 API 中也没有的。而是我单独添加的
//
DWORD CeGetPrivateProfileKeyNames(
          LPCTSTR lpAppName,
          LPTSTR lpReturnedString,
          DWORD nSize,                //缓冲区的字符数
          LPCTSTR lpFileName
          )
{
 DWORD ret = 0;                    //返回值,拷贝的字符数量
 DWORD remainSize = nSize - 2;    //缓冲区当前所能能够接纳的字符数量
 DWORD copySize;                    //本次循环中需要拷贝的字符数量
 bool bFindSection = false;        //是否已经找到Section
 TCHAR line[ LINESIZE ];            //行缓冲区
 LPTSTR pItem;                    //指向当前键值对的写入地址
 TCHAR *pEqualChar;                //等号字符的在行中的位置
 FILE *stream;                    //流指针
 size_t sectionLength, lineLength;


 pItem = lpReturnedString; //指向缓冲区起始地址

 stream = t_fopen(lpFileName, _T("r"));
 if(stream == NULL)
 {
  return ret;
 }

 sectionLength = t_strlen(lpAppName);

 while(t_fgets(line, LINESIZE, stream) != NULL)
 {
  //缓冲区是否还有剩余空间?
  if(remainSize <= 0) break;

  //忽略注释行和空行
  if(line[0] == 0 || line[0] == ';') continue;
  lineLength = t_strlen(line);
  //注意:把LF(0xa)字符替换成0,这在UNICODE环境下可能出现结尾是LF)
  if(line[ lineLength - 1 ] == 0x0a)
  {
   line[ lineLength - 1 ] = 0;
   lineLength--;
   //注意此时可能会成为空字符串
   if(lineLength == 0) continue;
  }

  //尝试寻找到 section
  if(!bFindSection)
  {
   if(line[0] != '[') continue; //本行是否是 [section]
   //这里是我们想要的Section吗?
   //检查这一行的宽度是否正好是section长度加2, [lpAppName]
   if(line[sectionLength + 1] != ']') continue;
   if(t_strncmp(line+1, lpAppName, sectionLength) != 0) continue;
   //Now Section will appear on next line
   bFindSection = true;           
   continue;
  }

  //查找Key, Section End?
  if(line[0]=='[') break; //遇到了下一个


  //copy the keyname to buffer, 注意ncpy不会复制结尾的0字符

  //LINE: "keyName = "
  //       |       |
  //     line   pEqualChar       

  //找出‘=’字符的位置
  pEqualChar = t_strchr(line, '=');
  if(pEqualChar != NULL)
  {
   //找到了‘=’字符,(pEqualChar - line)是key的长度
   copySize = min( remainSize,  pEqualChar - line );
  }
  else
  {
   //本行中不存在‘=’字符,对于合法文件来说不会出现此种情况
   copySize = min( remainSize, lineLength );
  }

  t_strncpy(pItem, line, copySize);
  //最佳一个0字符
  pItem[copySize] = 0;

  //缩小缓冲区剩余字符数量remainSize,和当前写入位置pItem
  ret += (copySize + 1); //加1是为了统计结尾的0字符
  remainSize -= (copySize + 1);
  pItem += (copySize + 1);
 }

 fclose(stream);

 if(bFindSection)
 {
  //再次对缓冲区追加一个0 字符
  *pItem = 0;
 }
 return ret;
}

 

3. 使用说明

CString  strRoad = L"\\System\\test\\BTDeviceInfo.ini";

TCHAR buffer[128];
 int ComNum;

 CeGetPrivateProfileString(_T("Section1"), _T("btName"), _T("defaultValue"), buffer,sizeof(buffer), strRoad);
 ComNum = CeGetPrivateProfileInt(_T("Section1"), _T("btCom"), -1, strRoad);

str.Format(L"%s",BTInfo.Name);
  CeWritePrivateProfileString(_T("Section1"), _T("btName"), str,strRoad);
  str.Format(L"%08x",BTInfo.Addr);
  CeWritePrivateProfileString(_T("Section1"), _T("btAddr"), str,strRoad);
  str.Format(L"%d",BTInfo.ComNum);
  CeWritePrivateProfileString(_T("Section1"), _T("btCom"), str,strRoad);
  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值