• VC++中文件操作(二)--- .ini文件、CFile64


      各种关于文件的操作在程序设计中是十分常见,如果能对其各种操作都了如指掌,就可以根据实际情况找到最佳的解决方案,从而在较短的时间内编写出高效的代码,因而熟练的掌握文件操作是十分重要的。本文将对Visual C++中有关文件操作进行全面的介绍,并对在文件操作中经常遇到的一些疑难问题进行详细的分析。

    VC++中文件操作(二)

     ***************************************************************************
    ××××××××××第一、VC有关文件操作,参考资料2
    ***************************************************************************

    在我们写的程序当中,总有一些配置信息需要保存下来,以便完成程序的功能,最简单的办法就是将这些信息写入INI文件中,程序初始化时再读入.具体应用如下:

      一.将信息写入.INI文件中.

      1.所用的WINAPI函数原型为:

    BOOL WritePrivateProfileString( 
    LPCTSTR lpAppName, 
    LPCTSTR lpKeyName, 
    LPCTSTR lpString, 
    LPCTSTR lpFileName 
    );

      其中各参数的意义:

       LPCTSTR lpAppName 是INI文件中的一个字段名.

       LPCTSTR lpKeyName 是lpAppName下的一个键名,通俗讲就是变量名.

       LPCTSTR lpString 是键值,也就是变量的值,不过必须为LPCTSTR型或CString型的.

       LPCTSTR lpFileName 是完整的INI文件名.

      2.具体使用方法:设现有一名学生,需把他的姓名和年龄写入 c:studstudent.ini 文件中.

    CString strName,strTemp; 
    int nAge; 
    strName="张三"; 
    nAge=12; 
    ::WritePrivateProfileString("StudentInfo","Name",strName,"c:\stud\student.ini");

      此时c:studstudent.ini文件中的内容如下:

       [StudentInfo] 
       Name=张三

      3.要将学生的年龄保存下来,只需将整型的值变为字符型即可:

    strTemp.Format("%d",nAge); 
    ::WritePrivateProfileString("StudentInfo","Age",strTemp,"c:\stud\student.ini");


     二.将信息从INI文件中读入程序中的变量.

      1.所用的WINAPI函数原型为:

    DWORD GetPrivateProfileString( 
    LPCTSTR lpAppName, 
    LPCTSTR lpKeyName, 
    LPCTSTR lpDefault, 
    LPTSTR lpReturnedString, 
    DWORD nSize, 
    LPCTSTR lpFileName 
    );

      其中各参数的意义:

       前二个参数与 WritePrivateProfileString中的意义一样.

       lpDefault : 如果INI文件中没有前两个参数指定的字段名或键名,则将此值赋给变量.

       lpReturnedString : 接收INI文件中的值的CString对象,即目的缓存器.

       nSize : 目的缓存器的大小.

       lpFileName : 是完整的INI文件名.

      2.具体使用方法:现要将上一步中写入的学生的信息读入程序中.

    CString strStudName; 
    int nStudAge; 
    GetPrivateProfileString("StudentInfo","Name","默认姓名",strStudName.GetBuffer(MAX_PATH),MAX_PATH,"c:\stud\student.ini");

      执行后 strStudName 的值为:"张三",若前两个参数有误,其值为:"默认姓名".

      3.读入整型值要用另一个WINAPI函数:

    UINT GetPrivateProfileInt( 
    LPCTSTR lpAppName, 
    LPCTSTR lpKeyName, 
    INT nDefault, 
    LPCTSTR lpFileName 
    );

      这里的参数意义与上相同.使用方法如下:

    nStudAge=GetPrivateProfileInt("StudentInfo","Age",10,"c:\stud\student.ini");


    三.循环写入多个值,设现有一程序,要将最近使用的几个文件名保存下来,具体程序如下:

      1.写入:

    CString strTemp,strTempA; 
    int i; 
    int nCount=6; 
    file://共有6个文件名需要保存 
    for(i=0;i {strTemp.Format("%d",i); 
    strTempA=文件名; 
    file://文件名可以从数组,列表框等处取得. 
    ::WritePrivateProfileString("UseFileName","FileName"+strTemp,strTempA, 
    "c:\usefile\usefile.ini"); 

    strTemp.Format("%d",nCount); 
    ::WritePrivateProfileString("FileCount","Count",strTemp,"c:\usefile\usefile.ini"); 
    file://将文件总数写入,以便读出.

      2.读出:

    nCount=::GetPrivateProfileInt("FileCount","Count",0,"c:\usefile\usefile.ini"); 
    for(i=0;i {strTemp.Format("%d",i); 
    strTemp="FileName"+strTemp; 
    ::GetPrivateProfileString("CurrentIni",strTemp,"default.fil", strTempA.GetBuffer(MAX_PATH),MAX_PATH,"c:\usefile\usefile.ini");

    file://使用strTempA中的内容.

    }

      补充四点: 
       1.INI文件的路径必须完整,文件名前面的各级目录必须存在,否则写入不成功,该函数返回 FALSE 值. 
       2.文件名的路径中必须为 \ ,因为在VC++中, \ 才表示一个 . 
       3.也可将INI文件放在程序所在目录,此时 lpFileName 参数为: ".\student.ini".

     1  //---------------------------------------------------------------------------------- 
     2 /* 
     3 类名:CIni 
     4 版本:v2.0 
     5 最后更新: 
     6 v2.0 
     7 梦小孩于2004年2月14日情人节 
     8 加入高级操作的功能 
     9 v1.0 
    10 梦小孩于2003年某日 
    11 一般操作完成 
    12 
    13 类描述: 
    14 本类可以于.ini文件进行操作 
    15 */ 
    16 
    17 文件 1: 
    18 
    19 #pragma once 
    20 
    21 #include "afxTempl.h" 
    22 
    23 class CIni 
    24 { 
    25 private: 
    26 CString m_strFileName; 
    27 public: 
    28 CIni(CString strFileName):m_strFileName(strFileName) 
    29 { 
    30 } 
    31 public: 
    32 //一般性操作: 
    33 BOOL SetFileName(LPCTSTR lpFileName); //设置文件名 
    34 CString GetFileName(void); //获得文件名 
    35 BOOL SetValue(LPCTSTR lpSection, LPCTSTR lpKey, LPCTSTR lpValue,bool bCreate=true); //设置键值,bCreate是指段名及键名未存在时,是否创建。 
    36 CString GetValue(LPCTSTR lpSection, LPCTSTR lpKey); //得到键值. 
    37 BOOL DelSection(LPCTSTR strSection); //删除段名 
    38 BOOL DelKey(LPCTSTR lpSection, LPCTSTR lpKey); //删除键名 
    39 
    40 
    41 public: 
    42 //高级操作: 
    43 int GetSections(CStringArray& arrSection); //枚举出全部的段名 
    44 int GetKeyValues(CStringArray& arrKey,CStringArray& arrValue,LPCTSTR lpSection); //枚举出一段内的全部键名及值 
    45 
    46 BOOL DelAllSections(); 
    47 
    48 }; 

     文件 2: 

      1 #include "StdAfx.h" 
      2 #include "ini.h" 
      3 
      4 #define MAX_ALLSECTIONS 2048 //全部的段名 
      5 #define MAX_SECTION 260 //一个段名长度 
      6 #define MAX_ALLKEYS 6000 //全部的键名 
      7 #define MAX_KEY 260 //一个键名长度 
      8 
      9 BOOL CIni::SetFileName(LPCTSTR lpFileName) 
     10 { 
     11 CFile file; 
     12 CFileStatus status; 
     13 
     14 if(!file.GetStatus(lpFileName,status)) 
     15 return TRUE; 
     16 
     17 m_strFileName=lpFileName; 
     18 return FALSE; 
     19 } 
     20 
     21 CString CIni::GetFileName(void) 
     22 { 
     23 return m_strFileName; 
     24 } 
     25 
     26 BOOL CIni::SetValue(LPCTSTR lpSection, LPCTSTR lpKey, LPCTSTR lpValue,bool bCreate) 
     27 { 
     28 TCHAR lpTemp[MAX_PATH] ={0}; 
     29 
     30 //以下if语句表示如果设置bCreate为false时,当没有这个键名时则返回TRUE(表示出错) 
     31 //!*&*none-value*&!* 这是个垃圾字符没有特别意义,这样乱写是防止凑巧相同。 
     32 if (!bCreate) 
     33 { 
     34 GetPrivateProfileString(lpSection,lpKey,"!*&*none-value*&!*",lpTemp,MAX_PATH,m_strFileName); 
     35 if(strcmp(lpTemp,"!*&*none-value*&!*")==0) 
     36 return TRUE; 
     37 } 
     38 
     39 if(WritePrivateProfileString(lpSection,lpKey,lpValue,m_strFileName)) 
     40 return FALSE; 
     41 else 
     42 return GetLastError(); 
     43 } 
     44 
     45 CString CIni::GetValue(LPCTSTR lpSection, LPCTSTR lpKey) 
     46 { 
     47 DWORD dValue; 
     48 TCHAR lpValue[MAX_PATH] ={0}; 
     49 
     50 dValue=GetPrivateProfileString(lpSection,lpKey,"",lpValue,MAX_PATH,m_strFileName); 
     51 return lpValue; 
     52 } 
     53 
     54 BOOL CIni::DelSection(LPCTSTR lpSection) 
     55 { 
     56 if(WritePrivateProfileString(lpSection,NULL,NULL,m_strFileName)) 
     57 return FALSE; 
     58 else 
     59 return GetLastError(); 
     60 } 
     61 
     62 BOOL CIni::DelKey(LPCTSTR lpSection, LPCTSTR lpKey) 
     63 { 
     64 if(WritePrivateProfileString(lpSection,lpKey,NULL,m_strFileName)) 
     65 return FALSE; 
     66 else 
     67 return GetLastError(); 
     68 } 
     69 
     70 
     71 int CIni::GetSections(CStringArray& arrSection) 
     72 { 
     73 /* 
     74 本函数基础: 
     75 GetPrivateProfileSectionNames - 从 ini 文件中获得 Section 的名称 
     76 如果 ini 中有两个 Section: [sec1] 和 [sec2],则返回的是 'sec1',0,'sec2',0,0 ,当你不知道 
     77 ini 中有哪些 section 的时候可以用这个 api 来获取名称 
     78 */ 
     79 int i; 
     80 int iPos=0; 
     81 int iMaxCount; 
     82 TCHAR chSectionNames[MAX_ALLSECTIONS]={0}; //总的提出来的字符串 
     83 TCHAR chSection[MAX_SECTION]={0}; //存放一个段名。 
     84 GetPrivateProfileSectionNames(chSectionNames,MAX_ALLSECTIONS,m_strFileName); 
     85 
     86 //以下循环,截断到两个连续的0 
     87 for(i=0;i<MAX_ALLSECTIONS;i++) 
     88 { 
     89 if (chSectionNames[i]==0) 
     90 if (chSectionNames[i]==chSectionNames[i+1]) 
     91 break; 
     92 } 
     93 
     94 iMaxCount=i+1; //要多一个0号元素。即找出全部字符串的结束部分。 
     95 arrSection.RemoveAll();//清空原数组 
     96 
     97 for(i=0;i<iMaxCount;i++) 
     98 { 
     99 chSection[iPos++]=chSectionNames[i]; 
    100 if(chSectionNames[i]==0) 
    101 { 
    102 arrSection.Add(chSection); 
    103 memset(chSection,0,MAX_SECTION); 
    104 iPos=0; 
    105 } 
    106 
    107 } 
    108 
    109 return (int)arrSection.GetSize(); 
    110 } 
    111 
    112 int CIni::GetKeyValues(CStringArray& arrKey,CStringArray& arrValue, LPCTSTR lpSection) 
    113 { 
    114 /* 
    115 本函数基础: 
    116 GetPrivateProfileSection- 从 ini 文件中获得一个Section的全部键名及值名 
    117 如果ini中有一个段,其下有 "段1=值1" "段2=值2",则返回的是 '段1=值1',0,'段2=值2',0,0 ,当你不知道 
    118 获得一个段中的所有键及值可以用这个。 
    119 */ 
    120 int i; 
    121 int iPos=0; 
    122 CString strKeyValue; 
    123 int iMaxCount; 
    124 TCHAR chKeyNames[MAX_ALLKEYS]={0}; //总的提出来的字符串 
    125 TCHAR chKey[MAX_KEY]={0}; //提出来的一个键名 
    126 
    127 GetPrivateProfileSection(lpSection,chKeyNames,MAX_ALLKEYS,m_strFileName); 
    128 
    129 for(i=0;i<MAX_ALLKEYS;i++) 
    130 { 
    131 if (chKeyNames[i]==0) 
    132 if (chKeyNames[i]==chKeyNames[i+1]) 
    133 break; 
    134 } 
    135 
    136 iMaxCount=i+1; //要多一个0号元素。即找出全部字符串的结束部分。 
    137 arrKey.RemoveAll();//清空原数组 
    138 arrValue.RemoveAll(); 
    139 
    140 for(i=0;i<iMaxCount;i++) 
    141 { 
    142 chKey[iPos++]=chKeyNames[i]; 
    143 if(chKeyNames[i]==0) 
    144 { 
    145 strKeyValue=chKey; 
    146 arrKey.Add(strKeyValue.Left(strKeyValue.Find("="))); 
    147 arrValue.Add(strKeyValue.Mid(strKeyValue.Find("=")+1)); 
    148 memset(chKey,0,MAX_KEY); 
    149 iPos=0; 
    150 } 
    151 
    152 } 
    153 
    154 return (int)arrKey.GetSize(); 
    155 } 
    156 
    157 BOOL CIni::DelAllSections() 
    158 { 
    159 int nSection; 
    160 CStringArray arrSection; 
    161 nSection=GetSections(arrSection); 
    162 for(int i=0;i<nSection;i++) 
    163 { 
    164 if(DelSection(arrSection[i])) 
    165 return GetLastError(); 
    166 } 
    167 return FALSE; 
    168 } 
    169 
    170 
    171 使用方法: 
    172 CIni ini("c:\a.ini"); 
    173 int n; 
    174 
    175 /*获得值 
    176 TRACE("%s",ini.GetValue("段1","键1")); 
    177 */ 
    178 
    179 /*添加值 
    180 ini.SetValue("自定义段","键1","值"); 
    181 ini.SetValue("自定义段2","键1","值",false); 
    182 */ 
    183 
    184 /*枚举全部段名 
    185 CStringArray arrSection; 
    186 n=ini.GetSections(arrSection); 
    187 for(int i=0;i<n;i++) 
    188 TRACE("%s
    ",arrSection[i]); 
    189 */ 
    190 
    191 /*枚举全部键名及值 
    192 CStringArray arrKey,arrValue; 
    193 n=ini.GetKeyValues(arrKey,arrValue,"段1"); 
    194 for(int i=0;i<n;i++) 
    195 TRACE("键:%s
    值:%s
    ",arrKey[i],arrValue[i]); 
    196 */ 
    197 
    198 /*删除键值 
    199 ini.DelKey("段1","键1"); 
    200 */ 
    201 
    202 /*删除段 
    203 ini.DelSection("段1"); 
    204 */ 
    205 
    206 /*删除全部 
    207 ini.DelAllSections(); 
    208 */
    

     ***************************************************************************
    ××××××××××第二、VC有关文件操作,参考资料2
    ***************************************************************************

    随着Windows 2000和XP的普及,现在的大文件越来越多,而VC6中MFC的CFile类只支持不大于4GB的文件, 原因在于CFile类中使用了32位整型来处理文件,32位数的范围是2的32次方(4GB),超过这个范围的文件CFile就管不了,微软.Net中VC7的CFile类支持大于4GB的文件,而.Net还不普及,开发桌面应用VC6还是首选,所以我们可以参照VC7写一个CFile的继承类CFile64,使它支持大于4GB的文件: 

    1.头文件  File64.h

     1 class CFile64 : public CFile
     2 {
     3 public:
     4 
     5 // Attributes
     6  ULONGLONG GetPosition();
     7 
     8 
     9 // Overridables
    10 
    11  virtual ULONGLONG Seek(LONGLONG lOff, UINT nFrom);
    12  virtual void SetLength(ULONGLONG dwNewLen);
    13  ULONGLONG GetLength() ;
    14 
    15  virtual void LockRange(ULONGLONG dwPos, ULONGLONG dwCount);
    16  virtual void UnlockRange(ULONGLONG dwPos, ULONGLONG dwCount);
    17 
    18 };

    2.源文件  File64.cpp

     1 #include "stdafx.h"
     2 #include "file64.h"
     3 
     4 ////////////////////////////////////////////////////////////////////////////
     5 // CFile64 implementation
     6 
     7 
     8 ULONGLONG CFile64::Seek(LONGLONG lOff, UINT nFrom)
     9 {
    10  ASSERT_VALID(this);
    11  ASSERT((HANDLE)m_hFile != INVALID_HANDLE_VALUE);
    12  ASSERT(nFrom == begin || nFrom == end || nFrom == current);
    13  ASSERT(begin == FILE_BEGIN && end == FILE_END && current == FILE_CURRENT);
    14 
    15    LARGE_INTEGER liOff;
    16 
    17    liOff.QuadPart = lOff;
    18  liOff.LowPart = ::SetFilePointer((HANDLE)m_hFile, liOff.LowPart, &liOff.HighPart,
    19    (DWORD)nFrom);
    20  if (liOff.LowPart  == (DWORD)-1)
    21    if (::GetLastError() != NO_ERROR)
    22      CFileException::ThrowOsError((LONG)::GetLastError(), m_strFileName);
    23 
    24  return liOff.QuadPart;
    25 }
    26 
    27 ULONGLONG CFile64::GetPosition() 
    28 {
    29  ASSERT_VALID(this);
    30  ASSERT((HANDLE)m_hFile != INVALID_HANDLE_VALUE);
    31 
    32    LARGE_INTEGER liPos;
    33    liPos.QuadPart = 0;
    34  liPos.LowPart = ::SetFilePointer((HANDLE)m_hFile, liPos.LowPart, &liPos.HighPart , FILE_CURRENT);
    35  if (liPos.LowPart == (DWORD)-1)
    36    if (::GetLastError() != NO_ERROR)
    37      CFileException::ThrowOsError((LONG)::GetLastError(), m_strFileName);
    38 
    39  return liPos.QuadPart;
    40 }
    41 
    42 void CFile64::LockRange(ULONGLONG dwPos, ULONGLONG dwCount)
    43 {
    44  ASSERT_VALID(this);
    45  ASSERT((HANDLE)m_hFile != INVALID_HANDLE_VALUE);
    46 
    47    ULARGE_INTEGER liPos;
    48    ULARGE_INTEGER liCount;
    49 
    50    liPos.QuadPart = dwPos;
    51    liCount.QuadPart = dwCount;
    52  if (!::LockFile((HANDLE)m_hFile, liPos.LowPart, liPos.HighPart, liCount.LowPart, 
    53    liCount.HighPart))
    54    {
    55   CFileException::ThrowOsError((LONG)::GetLastError(), m_strFileName);
    56    }
    57 }
    58 
    59 void CFile64::UnlockRange(ULONGLONG dwPos, ULONGLONG dwCount)
    60 {
    61  ASSERT_VALID(this);
    62  ASSERT((HANDLE)m_hFile != INVALID_HANDLE_VALUE);
    63 
    64    ULARGE_INTEGER liPos;
    65    ULARGE_INTEGER liCount;
    66 
    67    liPos.QuadPart = dwPos;
    68    liCount.QuadPart = dwCount;
    69  if (!::UnlockFile((HANDLE)m_hFile, liPos.LowPart, liPos.HighPart, liCount.LowPart,
    70    liCount.HighPart))
    71    {
    72   CFileException::ThrowOsError((LONG)::GetLastError(), m_strFileName);
    73    }
    74 }
    75 
    76 void CFile64::SetLength(ULONGLONG dwNewLen)
    77 {
    78  ASSERT_VALID(this);
    79  ASSERT((HANDLE)m_hFile != INVALID_HANDLE_VALUE);
    80 
    81  Seek(dwNewLen, (UINT)begin);
    82 
    83  if (!::SetEndOfFile((HANDLE)m_hFile))
    84   CFileException::ThrowOsError((LONG)::GetLastError(), m_strFileName);
    85 }
    86 
    87 ULONGLONG CFile64::GetLength() 
    88 {
    89  ASSERT_VALID(this);
    90 
    91    ULARGE_INTEGER liSize;
    92    liSize.LowPart = ::GetFileSize((HANDLE)m_hFile, &liSize.HighPart);
    93    if (liSize.LowPart == (DWORD)-1)
    94    if (::GetLastError() != NO_ERROR)
    95    CFileException::ThrowOsError((LONG)::GetLastError(), m_strFileName);
    96 
    97  return liSize.QuadPart;
    98 }
    /////////////////////////////////////////////////////////////////////////////

    LONGLONG是64位整型,这样在理论上可支持的最大文件为18000000000GB,你也可以根据自己的需要重载CFile的其他函数

    整理自:http://www.cnblogs.com/lidabo/p/3470085.html

  • 相关阅读:
    状态模式作业
    建造者模式作业
    关于 IIS 上的 Speech 设置
    装饰模式作业
    《软件架构与设计模式》关于 抽象工厂模式 的一个小例子
    谈一谈为什么我要创建个人博客
    C#网站发布在IIS10上,Access数据库读取为空白的解决方案
    广义表 Head Tail
    c# asp.net4.0尚未在web服务器上注册
    装饰者模式(例子)
  • 原文地址:https://www.cnblogs.com/vranger/p/9380493.html
Copyright © 2020-2023  润新知