65.9K
CodeProject 正在变化。 阅读更多。
Home

Windows 中的 UTF-8 - INI 文件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.94/5 (6投票s)

2020年4月2日

MIT

4分钟阅读

viewsIcon

11354

downloadIcon

317

如何在 Windows INI 文件中处理 UTF-8

引言

在我之前的文章“在 Windows 中使用 UTF-8”中,我展示了如何仅使用两个函数 utf8::narrowutf8::widen 来处理 UTF-8。 对于一般的文件 I/O,您只需要将文件名从 UTF-8 转换为 UTF-16,所有的读写函数保持不变

  FILE *f = utf8::fopen (u8"ܐܪܡܝܐ.txt", "w");

  fputs (u8"This text is in Aramaic ܐܪܡܝܐ", f);
  fclose (f);

有一种情况不属于这些规则的涵盖范围:INI 文件,在 Microsoft 的术语中也被称为“配置文件”。 尽管有许多其他存储应用程序设置的方法,但 INI 文件仍然被广泛使用,原因要么是兼容性,要么是它们易于使用。

问题是用于读写 INI 文件的基本 Windows API 调用 GetPrivateProfileStringPutPrivateProfileString 在一个 API 调用中结合了文件名和要读写的信息。 例如,这是 GetPrivateProfileStringW 函数的签名

DWORD GetPrivateProfileStringW(
  LPCWSTR lpAppName,
  LPCWSTR lpKeyName,
  LPCWSTR lpDefault,
  LPWSTR  lpReturnedString,
  DWORD   nSize,
  LPCWSTR lpFileName
);

如果我们使用 utf8::widen 函数来转换所有 UTF-8 字符串,最终得到的 INI 文件将包含 UTF-16 字符。

解决方案是完全忘记 Windows API 函数,并构建我们自己的实现来访问 INI 文件。 这绝不是您可以找到的 INI 文件的唯一实现。 有关实现的列表,您可以查看 Wikipedia 页面。 其中一些可能有点过分炒作; 其中一个项目声称是“用 C 编写的终极且最一致的 INI 文件解析器库”。 我唯一的声明是,我的实现努力与原始 Windows API 尽可能兼容。

因此,您将找不到对文件格式的任意扩展,并且我进行了大量测试以识别不同的极端情况。 这是我通过尝试对原始 Windows API 进行不同组合的调用而发现的规则

  • 只有以分号开头的行是注释行(哈希在 Windows API 中不被视为注释)。
  • 没有尾随注释; 等号“=”之后的任何内容都是键值的一部分。
  • 前导和尾随空格都会从返回的字符串和参数中删除。

与 Windows API 相比,唯一的更改是

  • 行长默认为 1024 (INI_BUFFER_SIZE 值),而 Windows 将其限制为 256 个字符。
  • 没有路径的文件在当前目录中,而 Windows 将它们放在 Windows 文件夹中。

实现

INI 文件被实现为 IniFile 对象。 像在下面的代码中一样,基本成员函数 IniFile::GetStringIniFile::PutString 允许您在 INI 文件中读写设置

  utf8::IniFile test ("test.ini");
  test.PutString ("key1", "value11", "section1");
  string val = test.GetString ("key1", "section1");

原始 Windows API 仅处理 INI 文件的两种数据类型:字符串和整数。

(GetPrivateProfileStringGetPrivateProfileInt 函数)。 我认为将这些函数扩展到其他数据类型并添加一些实用函数很有用。 这不是文件格式的扩展; 这只是用于访问这些文件的 API 的扩展。 以下是其中一些功能

  • PutIntGetInt 用于整数值
  • PutDoubleGetDouble 用于浮点值
  • PutBoolGetBool 用于布尔变量(读取时,代码理解诸如“on”或“0”或“OFF”之类的东西)
  • PutColorGetColor 用于 RGB 颜色表示
  • PutFontGetFont 用于保存和检索字体设置
  • HasKeyHasSection 用于检查 INI 文件中是否存在键或节

查看代码时,有几个有趣的点。

INI 文件没有内存缓冲。 所有内容都尽快写入磁盘。 这是一个设计决定,因为

  1. 这就是 Windows 所做的,我想尽可能兼容,而且
  2. 当应用程序崩溃或以其他方式意外结束时,参数没有被保存,这非常烦人。 这种缺点是 INI 文件的效率降低,但它们并非旨在成为通用数据文件。

此外,每次在 INI 文件中写入一个键时,都会重新写入整个文件; 正如我所说,效率不是一个设计目标。

结论

本文中显示的代码使使用 UTF-8 编码在 INI 文件中保留应用程序设置变得容易。

本系列关于 Windows 中 UTF-8 的文章到此结束。 本系列的前两篇文章是

作为参考,本文包含的代码也包含前几篇文章的代码。

历史

  • 2020 年 4 月 2 日:初始版本
© . All rights reserved.