主页C++ Builder 资料C++ Builder 编程技巧文件处理INI 文件处理
C++ Builder 串口控件
C++ Builder 编程技巧
字符串及文字处理
多媒体处理
图片处理
文件处理
 • INI 文件处理
 • JSON 解析和生成
 • CHM 帮助文件
界面处理
C++ Builder 操作指南
C++ Builder 参考手册
网友留言/技术支持
INI 文件处理 - 文件处理
 • C++ Builder 支持的 ini 文件的结构
   · 简单的 ini 文件的结构
   · 含有 SubSections 的 ini 文件结构
 • C++ Builder 处理 ini 文件的头文件
 • 使用 TMemIniFile 处理 ini 文件,支持 UNICODE UTF-16, UTF-8
   · 指定 ini 文件的文件名和字符编码
   · AutoSave 属性和 UpdateFile() 方法
   · 读写数据
   · 删除数据
   · 读取 Sections
   · 删除 Sections
   · 整体文件的数据操作
   · TMemIniFile 的属性成员
 • 使用 TIniFile 处理 ini 文件,过时了的处理方法
 • TMemIniFile 和 TIniFile,应该使用哪一个,他们有什么区别?

C++ Builder 支持的 ini 文件的结构

简单的 ini 文件的结构

[Section1]
Indent1=Value1
Indent2=Value2

[Section2]
Indent3=Value3
Indent4=Value4

含有 SubSections 的 ini 文件结构

注1: 不要混用 “.”, “/” 和 “\” 做分割符,程序里面的写法要和文件里面的一致,
     例如 "Section1.SubSection1" 只是对应 [Section1.SubSection1] 而不对应 [Section1/SubSection1];
注2: 在 C/C++ 里面 “\” 是需要有转义符的,在程序里面不是 "Section1\SubSection1" 而是 "Section1\\SubSection1"。

用 . 分割 SubSections 的 ini 文件 用 / 分割 SubSections 的 ini 文件 用 \ 分割 SubSections 的 ini 文件
[Section1]
Indent1=Value1
Indent2=Value2

[Section2]
Indent3=Value3
Indent4=Value4

[Section1.SubSection1]
Indent5=Value5
Indent6=Value6
Indent7=Value7

[Section1.SubSection2]
Indent8=Value8
Indent9=Value9

[Section1.SubSection2.SubSubSec1]
IndentA=ValueA
IndentB=ValueB
IndentC=ValueC

[Section1.SubSection2.SubSubSec2]
IndentD=ValueD
IndentE=ValueE
IndentF=ValueF
[Section1]
Indent1=Value1
Indent2=Value2

[Section2]
Indent3=Value3
Indent4=Value4

[Section1/SubSection1]
Indent5=Value5
Indent6=Value6
Indent7=Value7

[Section1/SubSection2]
Indent8=Value8
Indent9=Value9

[Section1/SubSection2/SubSubSec1]
IndentA=ValueA
IndentB=ValueB
IndentC=ValueC

[Section1/SubSection2/SubSubSec2]
IndentD=ValueD
IndentE=ValueE
IndentF=ValueF
[Section1]
Indent1=Value1
Indent2=Value2

[Section2]
Indent3=Value3
Indent4=Value4

[Section1\SubSection1]
Indent5=Value5
Indent6=Value6
Indent7=Value7

[Section1\SubSection2]
Indent8=Value8
Indent9=Value9

[Section1\SubSection2\SubSubSec1]
IndentA=ValueA
IndentB=ValueB
IndentC=ValueC

[Section1\SubSection2\SubSubSec2]
IndentD=ValueD
IndentE=ValueE
IndentF=ValueF

C++ Builder 处理 ini 文件的头文件

新版本 C++ Builder 的 ini 文件处理头文件为 #include <System.IniFiles.hpp>
老版本 C++ Builder 的 ini 文件处理头文件为 #include <IniFiles.hpp> 新版本目前保留了这个头文件 (说不定再更新哪个版本就没有了)。

TMemIniFile 和 TIniFile 都在这个头文件里面。

使用 TMemIniFile 处理 ini 文件

指定 ini 文件的文件名和字符编码

TMemIniFile *ini = new TMemIniFile(L"d:\\abc.ini"); // 系统默认的文本文件字符编码 (ANSI)

TMemIniFile *ini = new TMemIniFile(L"d:\\abc.ini", TEncoding::UTF8); // UTF-8 编码

TMemIniFile *ini = new TMemIniFile(L"d:\\abc.ini", TEncoding::Unicode); // UNICODE UTF-16

TEncoding *encBig5 = new TMBCSEncoding(950);
TMemIniFile *ini = new TMemIniFile(L"d:\\abc.ini", encBig5); // BIG5 编码

TEncoding *encGBK = new TMBCSEncoding(936);
TMemIniFile *ini = new TMemIniFile(L"d:\\abc.ini", encGBK); // GBK 编码

虽然 ini 文件可以中途改文字编码,例如:
ini->Encoding = TEncoding::UTF8;
但是最好不要这样做,可能会导致乱码。
如果需要给文件转编码,可以使用 TStringList,方法请点击这里

指定的字符编码和 ini 文件本身的编码不同,打开文件会报错,例如文件是 ANSI 编码的,按照 UTF-8 读取,会报错,抛出异常。

重命名文件:Rename(新文件名, bool Reload) 的第二个参数 Reload:

ini->Rename(L"d:\\b.ini",false); // Reload=false: 重命名为 b.ini,如果有这个文件,会覆盖,没有会新创建

ini->Rename(L"d:\\a.ini",true); // Reload=true: 放弃原来的文件,重新加载 a.ini 文件,如果没有会新创建

 

AutoSave 属性和 UpdateFile() 方法

默认情况,TMemIniFile 不会自动保存 ini 文件。
 • AutoSave 属性设为 true 的情况,会在销毁 TMemIniFile 对象时存盘;默认值为 false,在销毁 TMemIniFile 对象的时候不存盘。
 • 调用 UpdateFile() 方法,会把修改的内容存盘。一般情况,在修改 ini 之后,调用 UpdateFile() 存盘。

#include <memory>
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  std::auto_ptr<TMemIniFile>ini(new TMemIniFile(L"d:\\abc.ini",TEncoding::Unicode));
  ini->WriteInteger(L"OPTIONS",L"Volume",100);
  ini->WriteInteger(L"OPTIONS",L"Rate",0);
  ini->UpdateFile();
}

 

读写数据

下面表格是读取各种数据类型数据的方法,读取 [Section] 里面的值 Ident,如果值不存在,返回默认值 Default

读取数据的方法 函数原型 说明
ReadString UnicodeString __fastcall ReadString(const UnicodeString Section, const UnicodeString Ident, const UnicodeString Default); 读取字符串值
ReadInteger int __fastcall ReadInteger(const UnicodeString Section, const UnicodeString Ident, int Default); 读取整数值
ReadBool bool __fastcall ReadBool(const UnicodeString Section, const UnicodeString Ident, bool Default); 读取布尔值
ReadFloat double __fastcall ReadFloat(const UnicodeString Section, const UnicodeString Name, double Default); 读取浮点数值
ReadDate TDateTime __fastcall ReadDate(const UnicodeString Section, const UnicodeString Name, TDateTime Default); 读取日期
ReadTime TDateTime __fastcall ReadTime(const UnicodeString Section, const UnicodeString Name, TDateTime Default); 读取时间
ReadDateTime TDateTime __fastcall ReadDateTime(const UnicodeString Section, const UnicodeString Name, TDateTime Default); 读取日期和时间
ReadBinaryStream int __fastcall ReadBinaryStream(const UnicodeString Section, const UnicodeString Name, TStream* Value); 读取二进制数据

下面表格是写入数据的方法,把 Indent 的数据写入 [Section],值为 Value,如果 [Section] 或 Indent 不存在会新增,如果存在会改写。

写入数据的方法 函数原型 说明
WriteString void __fastcall WriteString(const UnicodeString Section, const UnicodeString Ident, const UnicodeString Value); 写入字符串值
WriteInteger void __fastcall WriteInteger(const UnicodeString Section, const UnicodeString Ident, int Value); 写入整数值
WriteBool void __fastcall WriteBool(const UnicodeString Section, const UnicodeString Ident, bool Value); 写入布尔值
WriteFloat void __fastcall WriteFloat(const UnicodeString Section, const UnicodeString Name, double Value); 写入浮点数
WriteDate void __fastcall WriteDate(const UnicodeString Section, const UnicodeString Name, TDateTime Value); 写入日期
WriteTime void __fastcall WriteTime(const UnicodeString Section, const UnicodeString Name, TDateTime Value); 写入时间
WriteDateTime void __fastcall WriteDateTime(const UnicodeString Section, const UnicodeString Name, TDateTime Value); 写入日期和时间
WriteBinaryStream void __fastcall WriteBinaryStream(const UnicodeString Section, const UnicodeString Name, TStream* Value); 写入二进制数据

判断是否存在 [Section] 里面的 Indent 值

判断数据是否存在 函数原型 说明
ValueExists bool __fastcall ValueExists(const UnicodeString Section, const UnicodeString Ident); 判断是否存在 [Section] 里面的 Indent

 

删除数据

删除数据 函数原型 说明
DeleteKey void __fastcall DeleteKey(const UnicodeString Section, const UnicodeString Ident); 删除 [Section] 里面的 Indent

 

读取 Sections

读取 Sections 函数原型 说明 (示例为处理 “含有 SubSections 的 ini 文件结构” 的结构示例表格里面的 “用 . 分割 SubSections 的 ini 文件”)
ReadSection void __fastcall ReadSection(const UnicodeString Section, TStrings* Strings); 获取 [Section] 里面所有的 Indent,例如:读取 "Section1.SubSection2" 得到的是:
Indent8
Indent9
ReadSections void __fastcall ReadSections(TStrings* Strings); 获取所有 Section 的名字,例如读取结构示例能够得到:
Section1
Section2
Section1.SubSection1
Section1.SubSection2
Section1.SubSection2.SubSubSec1
Section1.SubSection2.SubSubSec2
ReadSections void __fastcall ReadSections(const UnicodeString Section, TStrings* Strings); 获取所有名字以参数 Section 指定的字符串开头的 Section 的名字。如果 Section 给定的是空字符串,执行结果和前一个只有一个参数的 ReadSections 函数相同。
ReadSubSections void __fastcall ReadSubSections(const UnicodeString Section, TStrings* Strings, bool Recurse = false); 获取所有 SubSections 的名字,
例如获取 "Section1.SubSection2"
得到的是 SubSubSec1 和 SubSubSec2,
例如获取 "Section1"
得到的是 SubSection1, SubSection2, SubSection2.SubSubSec1, SubSection2.SubSubSec2
ReadSectionValues void __fastcall ReadSectionValues(const UnicodeString Section, TStrings* Strings); 获取 [Section] 里面所有的值,
例如获取 "Section1"
得到的是
Indent1=Value1
Indent2=Value2
SectionExists bool __fastcall SectionExists(const UnicodeString Section); 判断 [Section] 是否存在。

 

删除 Sections

删除 Sections 函数原型 说明
EraseSection void __fastcall EraseSection(const UnicodeString Section); 删除整个 [Section]

 

整体文件的数据操作

整体文件数据操作 函数原型 说明
Clear void __fastcall Clear(void); 清除整个 ini 文件的内容
GetStrings void __fastcall GetStrings(TStrings* const List); 获取整个 ini 文件的内容到 List
SetStrings void __fastcall SetStrings(TStrings* const List); 整个 ini 的文件内容更换为 List 的内容

 

TMemIniFile 的属性成员

属性 类型 说明
AutoSave bool 是否在销毁 TMemIniFile 对象时保存文件,默认为 false,不保存。
Modified bool ini 文件数据是否被修改过
CaseSensitive bool 关键字 (Section 和 Ident) 是否区分大小写
FileName UnicodeString 文件名 (只读),在创建对象时指定文件名,或者用 Rename() 改名。
Encoding TEncoding * 文件的字符编码

 

使用 TIniFile 处理 ini 文件

在使用上,TIniFile 和 TMemIniFile 只有两点不同的地方:
 • 不需要用 UpdateFile() 存盘,也不需要指定 AutoSave 属性,TIniFile 始终和文件同步,每次读写数据都是在读写文件;
 • 不能指定字符编码,始终使用默认的编码 (ANSI) 创建新的文件,读取的时候,支持 ANSI 和 UNICODE (UTF-16)

使用 TIniFile 的注意事项:
 • 不推荐使用 TIniFile,推荐使用 TMemIniFile 处理 ini 文件;
 • TIniFile 用的是过时的 API 函数 GetPrivateProfileString 和 WritePrivateProfileString 处理的 ini 文件,在 Windows 8 和 Windows 10 操作系统里面,出现访问系统盘里面的文件的兼容性问题。MSDN 里面描述的这两个 API 函数是为了兼容 16 位 Windows 应用保留的函数。
 • TIniFile 只能新建 ANSI 编码的文件,可以读写 ANSI 和 UNICODE (UTF-16) 编码的文件,无法读写 UTF-8 或其他编码的文件。

 

TMemIniFile 和 TIniFile,应该使用哪一个,他们有什么区别?

用下面的表格比较 TMemIniFile 和 TIniFile,很明显 TMemIniFile 获胜,应该使用 TMemIniFile。

项目 TMemIniFile TIniFile
读写方法 使用 TFileStream 读写文件,支持用 TEncoding 指定字符编码 使用的是过时的 GetPrivateProfileString 和 WritePrivateProfileString,这两个为了兼容 16 位 Windows 应用保留下来的 API 函数
兼容性 使用的是通用的文件处理方法,没有兼容性问题 在 Windows 8 之后的系统里面,读写系统盘里面的文件可能会出现无法读写文件内容的兼容性问题
文字编码 使用 TEncoding,支持所有操作系统支持的文字编码,包括 UNICODE (UTF-16)UTF-8 新创建的 ini 文件只能是 ANSI 编码的,可以读取 ANSIUNICODE (UTF-16) 的文件,无法读取 UTF-8 或其他编码的文件
效率 所有的内容都在内存里面处理,速度快,效率高 所有的处理都和文件同步,每次操作都读写文件,速度慢,效率低
使用区别 修改之后,需要用 UpdateFile() 存盘,也可以设 AutoSave 属性为 true,在修改之后自动保存文件。其他和 TIniFile 一样 不需要写存盘的代码,因为每次操作都和文件内容同步
下一页:JSON 解析和生成

C++ 爱好者 -- Victor Chen 的个人网站 www.cppfans.com 辽ICP备11016859号