字符集转换

字符集转换

g_convert() 系列函数封装了 iconv() 的功能。除了纯字符集转换之外,GLib 还有函数可以处理文件名编码这类复杂情况。

文件名编码

从历史上看,UNIX 没有为文件名定义编码:只要文件名不含有路径分隔符(“/”),它就是有效的。但是,显示文件名时可能需要转换:从创建时使用的字符集转换为应用程序运行所使用的字符集。考虑西班牙语文件名“Presentación.sxi”。如果创建它的应用程序使用 ISO-8859-1 进行编码,

Character:  P  r  e  s  e  n  t  a  c  i  ó  n  .  s  x  i
Hex code:   50 72 65 73 65 6e 74 61 63 69 f3 6e 2e 73 78 69

不过,如果应用程序使用 UTF-8,磁盘上的实际文件名将如下所示

Character:  P  r  e  s  e  n  t  a  c  i  ó     n  .  s  x  i
Hex code:   50 72 65 73 65 6e 74 61 63 69 c3 b3 6e 2e 73 78 69

Glib 对其字符串使用 UTF-8,而使用 GLib 的 GUI 工具包(例如 GTK)也这样做。如果你从文件系统(例如从 readdir()g_dir_read_name())中获取文件名,并且希望向用户显示该文件名,则需要将其转换为 UTF-8。相反的情况是用户键入想要保存的文件的名称:工具包将使用 UTF-8 对该字符串进行编码并提供给你,你需要在使用 open()fopen() 创建文件之前将其转换为文件名所用的字符集。

默认情况下,GLib 假定磁盘上的文件名使用 UTF-8 编码。这对于最近创建的文件系统来说是一个合理的假设:大多数应用程序都对字符串使用 UTF-8 编码,它们创建的文件名也使用该编码。但是,较旧的文件系统中可能仍然包含使用“旧”编码(例如 ISO-8859-1)创建的文件名。在这种情况下,出于兼容性原因,你可能希望指示 GLib 对文件名使用特定的编码,而不是 UTF-8。你可以通过在 G_FILENAME_ENCODING 环境变量中指定文件名编码来做到这一点。例如,如果你的安装对文件名使用 ISO-8859-1,你可以将以下内容放入 ~/.profile

export G_FILENAME_ENCODING=ISO-8859-1

GLib 提供了 g_filename_to_utf8()g_filename_from_utf8() 函数来执行必要的转换。这些函数将文件系统中 G_FILENAME_ENCODING 指定的编码中的文件名转换为 UTF-8,反之亦然。此图说明了这些函数是如何用于在 UTF-8 和文件系统中文件名编码之间进行转换的。

文件名编码之间的转换

应用程序编写人员清单

本节是对详细事项的实用总结,以确保你的应用程序正确处理文件名编码。

  1. 如果你从 `readdir()` 或 `gtk_file_chooser_get_filename()` 等函数中从文件系统获取文件名,则不必进行任何转换即可将该文件名传递给 `open()`、`rename()` 或 `fopen()` 等函数 — 这些是“原始”文件名,文件系统会对其进行理解。
  2. 如果您需要显示文件名称,请首先使用 g_filename_to_utf8() 将其转换为 UTF-8。如果转换失败,则显示类似“未知文件名称”的字符串。如果您希望将其传递给文件系统,则不要将此字符串转换回用于文件名的编码;而应使用原始文件名称。
  3. 例如,文字处理器的文档窗口可以在标题栏中显示“未知文件名称”,但仍然允许用户保存文件,因为它会在内部保留原始文件名称。当用户没有设置 G_FILENAME_ENCODING 环境变量而其文件名称未使用 UTF-8 进行编码时,就会发生这种情况。
  4. 如果您的用户界面允许用户键入文件名称以便进行保存或重命名,请使用 g_filename_from_utf8() 将其转换为文件系统中用于文件名的编码。将转换后的文件名称传递给 fopen() 之类的函数。如果转换失败,请要求用户输入不同的文件名称。例如,在将 G_FILENAME_ENCODING 设置为 ISO-8859-1 时,用户键入日语字符时会发生这种情况。