选择文本模式的编码
对于写入的文本文件,编码应基于文本特性选择,或适配外部程序对于生成文件的特定要求。如果没有外部要求,你可以遵循这一规则:对于具有数字、英文字母和符号的纯文本,使用 ANSI 编码(包含 128 个国际字符表格详见 字符串比较章节中讨论过)。处理各种语言或特殊字符时,使用 UTF-8 或 Unicode,即分别为:
int u8 = FileOpen("utf8.txt", FILE_WRITE | FILE_TXT | FILE_ANSI, 0, CP_UTF8);
|
例如,这些设置很适合用于将金融工具的名称保存到文件,因为它们有时候使用表示货币或交易模式的特殊字符。
读取你自己的文件应没有问题,因为在读取时只需指定与写入时的相同编码设置即可。然而,文本文件的来源可能各不相同。它们的编码可能未知,或者会未经通知而更改。因此,问题来了,如果一些文件以单字节字符串 (ANSI) 提供,一些是双字节字符串 (Unicode),而一些是 UTF-8 编码,该怎么办。
可以通过程序的 输入参数 来选择编码。然而,这仅对一个文件有效,如果你必须打开很多不同文件,它们的编码可能不匹配。因此,最好指示系统即时(根据文件)选择正确的模型。
MQL5 不允许 100% 自动检查和应用正确编码,然而,有一种用于读取各种文本文件的最通用的模式。为此,你需要设置 FileOpen 函数的以下输入参数:
int h = FileOpen(filename, FILE_READ | FILE_TXT | FILE_ANSI, 0, CP_UTF8); |
这幕后有几个因素。
首先,UTF-8 编码明确跳过上述任何 ANSI 编码中的 128 个字符(即,这些字符是“一对一”传输)。
其次,它对互联网协议来说是使用最广泛的。
再次,MQL5 具有针对两字节 Unicode 的附加内置分析,可让你在必要时将文件操作模式自动切换为 FILE_UNICODE,不论指定的参数如何。事实是,Unicode 格式的文件通常在开头有一对特殊标识符:0xFFFE 或者 0xFEFF。该序列称为字节顺序标记 (BOM)。这是必需的,因为我们已经知道,不同平台上数字的字节存储顺序可能不同(这在 整数中的字节顺序控制章节中讨论过)。
FILE_UNICODE 格式中,每字符使用 2 个字节整数(代码),因此字节顺序变得重要,不同于其它编码。Windows 字节顺序 BOM 是 0xFFFE。如果 MQL5 核心在一个文本文件的开头即找到该标签,则其读取模式将自动切换为 Unicode 模式。
我们看看不同模式设置如何处理不同编码的文本文件。为此,我们将使用 FileText.mq5 脚本以及具有相同内容但不同编码的若干文本文件(括号中是字节数大小):
- ansi1252.txt (50):European 编码 1252(在欧洲语言的 Windows 中,其将完整无损显示)
- unicode1.txt (102):两字节 Unicode,开头是固有的 Windows BOM 0xFFFE
- unicode2.txt (100):两字节 Unicode,没有 BOM(一般来说,BOM 可选)
- unicode3.txt (102):两字节 Unicode,开头是 Unix 固有的 BOM,0xFEFF
- utf8.txt (54):UTF-8 编码
在 OnStart 函数中,我们将以 FileOpen 的不同设置循环读取这些文件。请注意,使用 FileHandle(在 上一节中回顾过),我们不必担心关闭文件的问题:所有操作会在每次迭代中自动完成。
void OnStart()
|
FileReadString 函数从文件读取字符串。我们将在关于 读写变量的章节中探讨。
这里是个带有脚本执行结果的示例日志:
=====> UTF-8
|
unicode1.txt 文件始终被正确读取,因为它有 BOM 0xFFFE,系统忽略源代码中的设置。然而,如果标签缺失或为大端模式,则这种自动检测不起作用。同时,若设置了 FILE_UNICODE,我们便无法读取单字节文本和 UTF-8。
因此,前述 FILE_ANSI 和 CP_UTF8 的组合应被视为更能适应格式设置中的变化。仅当明确要求时,才建议选择特定国家代码页。
尽管在文本模式下处理文件时,API 为编程人员提供了极大帮助,但如果必要,我们可以避免 FILE_TXT 或 FILE_CSV 模式,而是以二进制模式 FILE_BINARY 打开一个文本文件。这将把解析文本和确定编码的所有复杂任务将由编程人员负责完成,但能够支持其它非标准格式。但要点在于,可以从以二进制模式打开的文件读取或写入文本。但是,反过来一般不行。以文本模式打开的带有任意数据的二进制文件(即,其不是仅包含字符串)将很大可能被解读为乱码文本。如果想要将二进制数据写入到一个文本文件,则首先使用 CryptEncode 函数和 CRYPT_BASE64 编码。