☰
Caché/IRIS终端中文乱码排查与修复:从编码对齐到UTF-8配置
2026/10/6 9:07:13 网站建设 项目流程

先交代一下背景。我在一家做医疗信息化的公司干了六七年,项目里跑的基本都是 InterSystems 的 Caché,这两年逐步换成 IRIS。平时被问得最多的问题,除了 cache 数据库许可证怎么处理、iris odbc 驱动下载装哪一个版本之外,就是:为什么我在 Caché 自带的终端里,一敲中文就乱码?

这个问题看起来小,实际排查起来却很绕。它在 Windows 上出现,在 Linux 上出现,在 telnet 远程连进去时出现,在服务器本地控制台也能出现;有时只是输入框里乱,有时是查询结果乱,有时是菜单和错误提示乱。不同情况背后其实指向同一个根源:终端会话里的“字符编码”没有对齐。数据还是那份数据,字符串还是那个字符串,但只要客户端用什么代码页解释、服务端用什么代码页输出、终端用什么字体画出来这三件事不一致,屏幕上就会给你一份“鬼画符”。

这篇我把自己的排查思路、实际验证过的修复步骤和一些反直觉的坑整理出来。适合的对象很明确:正在维护 Caché / IRIS,被自带终端中文乱码烦到的人。无论是 Windows 控制台还是 Linux 终端,不管是本地还是远程会话,都适用。你会拿到一套能直接抄的检查顺序,而不是零散的chcp 65001之类的偏方。

1. 乱码源头定位:先分清“数据烂了”和“显示没对齐”

1.1 先看存储层:Caché/IRIS 内部其实没那么容易“坏”

很多同事遇到乱码的第一反应是:数据库把中文存坏了。老实说,Caché 和 IRIS 对 Unicode 的支持比很多老牌关系库都要好。字符串在内部默认按 Unicode 存放,写入时是什么字符,读出来还是什么字符。你用write "中文"敲进去,再write <那个变量>,拿到的字节在内存里没有变化。

会出现“看起来像坏了”的结果,绝大多数情况是发生了两次“翻译”:第一次是 IRIS 向终端设备输出时,根据设备定义的编码把内部 Unicode 转成了某个字节流;第二次是终端程序拿到字节流后,按照自己的代码页/字体把它画出来。两次翻译只要有一次用错了字典,字符就变成了我们熟悉的锟斤拷或??。

所以我排查时第一步永远是:确认是“显示乱”还是“数据乱”。如果数据真的乱,问题通常在例程/文件的编码、导入导出参数、ODBC/JDBC 连接串上,跟终端关系不大;如果数据显示乱,问题就收敛到终端会话这一条链路上。

1.2 三种典型乱码形态,对应了三段不同链路

我这些年见过很多种“乱码”,归纳下来基本跳不出三类。

第一类是锟斤拷、烫烫烫这类无意义汉字组合,或者淇℃伅、濡傛灉这种“看着像汉字但读不通”的内容。这基本是同一个字符串,用一种编码写入、用另一种编码读出。比如数据本身是 UTF-8 字节流,终端却按 GBK 或 Latin-1 解码,就会变成这种形态。这类乱码修客户端最有效。

第二类是大量方框、问号或�。这种一般是终端字体里没有对应字形,或者代码页根本不支持这个字符集。比如把中文塞给一个默认的 DOS 代码页,结果只能是方块。这类乱码先卸责任,谁都别怪,把终端字体和代码页换成 UTF-8 就行。

第三类是“输入正常、查询乱”,或者反过来“查询正常、提示乱”。这种多发生在同一个终端进程里存在多套编码设置。IRIS 的终端支持按会话调整编码,如果你的连接配置文件把交互输入设成 A 编码,输出设成 B 编码,就会出现这种“薛定谔的乱码”。

乱码形态典型例子最可能的环节
汉字读不通锟斤拷、濡傛灉客户端/服务端编码不一致
方框、缺字� 或 □字体、代码页不支持
部分场景乱输入正常输出乱会话内编码配置不统一

1.3 几组命令,快速判断你的乱码属于哪一类

进入 Caché/IRIS 终端后,我通常会按顺序敲下面几组命令:

set t="中文测试" write t write $zv

write t是验证写出去能不能原样读出来。$zv显示的是 IRIS 版本,如果版本信息这种纯英文都正常,说明链路至少没坏到完全不通。

接着再跑:

write $system.Process.Version()

然后退出终端,在操作系统命令行里看一下当前环境的编码。Windows 下用chcp,Linux 下用locale。这一步最容易被忽略,但它几乎是所有乱码的共同起点。

要是终端里write t正常,但一旦执行do ^%SYSTEM这种菜单程序就乱,问题大概率在终端类型定义和字符集设置上,不是编码翻译,而是“终端能力协商”出问题。后面第 3 节会展开说。

2. 客户端环境这层,最容易改完就见效

如果你只是急着把眼前这坨乱码弄正常,我建议从客户端开始改。因为服务端配置通常已经固化在你公司的维护脚本里,而客户端是你马上就能动手的部分。

2.1 Windows 自带终端:代码页、字体、新版终端三层分别处理

Windows 下最经典的做法是切换代码页。在 CMD 里执行:

chcp 65001

这会告诉控制台“接下来请用 UTF-8 解释字节流”。打完再重新启动 IRIS 终端(注意要先退出再重新进来,同一个进程里切换有时不彻底),大部分中文就能恢复正常。如果你以前习惯用chcp 936(GBK),而在 IRIS 里数据已经按 UTF-8 输出,就会看到前面说的鑴嗗噭一类怪字。

只执行 chcp 还不够,有两个坑。

第一个坑是字体。CMD 默认的“点阵字体”对 Unicode 支持很有限,中文显示出来要么糊要么缺。建议把窗口字体换成“Consolas”或“新宋体/雅黑”,并在“属性 → 选项 → 当前代码页”里确认选择的是 UTF-8。如果你用的是 Windows Terminal,直接在主配置里把配置文件设为“Windows PowerShell”,然后把“使用 UTF-8”当作默认设置,问题会少很多。

第二个坑是版本差异。老版本 Windows 在chcp 65001状态下,CMD 的控制台 API 偶尔会有句子输出错位、光标乱跳的现象。遇到这种情况不要死磕 CMD,安装 Windows Terminal,或者在 IRIS 自带的终端客户端里直接改编码设置,都比硬啃 CMD 省事。IRIS 自己的终端客户端有编码切换入口,不同版本菜单位置不太一样,新版本一般在菜单栏 “Edit / Encoding” 或 “View / Encoding” 里,切换后立刻生效,不需要重启进程。

2.2 Linux 终端:locale 和 TERM 才是两个真正的开关

在 Linux 下维护 IRIS 的人,很多是 ssh 过去再敲iris session。乱码原因通常是这样几个:LANG没设好、终端模拟器的编码和字体没配对、以及会话建立时继承的编码环境不对。

先检查:

echo $LANG echo $TERM locale

如果你是中文环境,LANG应该是类似zh_CN.UTF-8;如果你是英文环境,直接用en_US.UTF-8也可以,只要后半截是 UTF-8,中文就能正确传输。常见的问题是LANG被写成了zh_CN.GB2312或者干脆没设置,终端模拟器拿到一串 UTF-8 字节却假设它是 GBK,自然乱码。

修改方式按发行版来,Debian/Ubuntu 写入/etc/default/locale,CentOS/RHEL 类写入/etc/locale.conf,临时测试就用export LANG=zh_CN.UTF-8验证当前会话。

这里要专门提一下终端复用工具和第三方终端,比如tmux、screen、Tabby 这类。它们本身不是编码问题制造者,但会“继承”输入终端的编码设置。如果你在 Windows 上的 Tabby 里用 UTF-8 连到 Linux,Linux 系统的LANG却是 GBK,Tabby 会很听话地把 GBK 内容原样送过来,你的 Windows 侧却按 UTF-8 解析,出来一定是乱码。所以用这类工具排查时,客户端和远程服务器的LANG要同时看,缺一个都会误判。

还有一个平时没人提但在生产环境很常见的场景:你用tmux attach恢复一个很久以前创建的会话,会话创建时的客户端编码可能和你现在完全不一样。恢复之后看到的全是乱码,但新开的会话却没问题。这种情况不用怀疑 IRIS,直接退出重进即可。

提示:第三方终端工具排查编码问题时,不要只改工具自身的字符集设置。工具只是“搬运工”,真正决定字节流怎么解释的是 session 建立时两侧的 locale 和代码页。

2.3 telnet/SSH 会话的编码协商:最容易被忽略的一环

IRIS 老用户可能还记得,早期 Caché 的终端是支持直接 telnet 上去的,有些老系统至今保留着 telnet 端口。telnet 客户端有一个特点:它默认按 NVT ASCII 模式解释字节流,遇到高位字节会做转换,中文这种字节很容易被它“好心办坏事”地改掉。如果公司里还有从 telnet 进%SYS的老流程,乱码几乎无法避免。

解决办法很直接:不要用操作系统自带的 telnet,改成第三方终端软件。PuTTY 连接后在 Translation 里把 Remote character set 设为 UTF-8,或者把 “Treat UTF-8 as multiple TELNET 255 sequences” 关掉;Windows 自带的 telnet 客户端尽量别用了,它的代码页硬编码得太厉害。SSH 场景相对好很多,因为 SSH 通道没有 NVT 这种中间层,你只需要把 ssh 客户端、服务器LANG、终端模拟器三者都对齐到 UTF-8。

如果公司规范里必须维持旧协议,有个折中方案:把终端类型从VT100改成ANSI或VT220,同时把 IRIS 服务端的终端设备编码设为 UTF-8。降低一层“翻译”,乱码概率会明显下降。这个设置在下一个章节讲。

3. IRIS/Caché 服务端设置:真正能“根治”的几张底牌

客户端改好之后,如果乱码依旧,或者一换电脑又乱,那就必须回头看服务端了。服务端配置不是每次都要改,但你必须知道它存在,否则只能反复在客户端打补丁。

3.1 管理门户里的终端类型、字符集和代码页设置

IRIS 的管理门户路径大致是:System Administration → Configuration → System → Terminal Settings。老版本 Caché 叫 “Terminal” 或 “Console” 配置,位置略有出入,但关键字是 Terminal 和 Encoding。

这里面最关键的是两个概念:终端类型(Terminal Type)和字符集(Charset)。终端类型决定 IRIS 如何解释你按下的功能键、方向键和退格键,常见值有VT100、VT220、ANSI、SCO;字符集决定 IRIS 向这个终端输出时用哪种代码页。很多系统默认终端类型是VT100,这在 20 年前没问题,但现在的中文终端、Windows Terminal、Tabby 对VT100的支持并不好,方向键会产生^[[A这种转义序列乱码,中文反而不一定乱。真正影响中文的是字符集,把它改成UTF-8,然后重启终端进程,90% 的服务端乱码会消失。

但我要提醒一句:终端类型不要随便从VT100改成ANSI,因为你们监控脚本里可能有人依赖老终端的行为,改完中文好了,监控脚本的屏幕抓取却坏了。生产环境改配置,先在一个临时命名空间或测试机上验证,再推到业务机,这不是流程问题,是血泪教训。

3.2 在 %SYS 下临时切换 UTF-8 的操作路径

如果你连门户都打不开,只想在当前终端会话里临时切换编码,IRIS 也留了路。进入%SYS命名空间:

zn "%SYS"

然后使用终端客户端的编码切换功能。不同版本位置不同,新版本终端在菜单 Edit 或 View 下面能找到 Encoding 相关项,点了之后会列出当前支持的代码页列表,选UTF-8或Unicode (UTF-8)。切换是会话级的,不影响其他连接,适合临时救急。

另外,你在%SYS下可以查看当前进程的 IO 配置信息,命令大致是:

write ##class(%SYSTEM.Process).IsUTF8()

这个方法如果返回 1,说明当前进程已经处于 UTF-8 模式;返回 0,则说明还在旧代码页模式。不同小版本方法名可能不同,在 IRIS 里可以打开帮助面板搜 “UTF-8”,能搜到更多相关信息。如果你所在版本的方法名不是这个,不要硬记代码,去做一件事:在帮助里看%SYSTEM.Process类的方法列表,找到带 UTF 或 Codepage 关键字的方法,按方法名调用即可。

3.3 例程与全局的存储编码,以及编译参数的坑

到这里,不少人会问:我把终端改成 UTF-8 了,但例程里的中文还是乱,为什么?

因为例程文件本身也有编码。Caché/IRIS 的例程可以通过 Studio、VSCode 或命令行导入,导入时如果不指定编码,IDE 会按自己的默认规则处理。如果你从 Windows 本地写好的代码带了一堆 UTF-8 中文注释,导入到 Linux 服务器上用LOAD命令,IDE 默认可能按 GBK 去读字节流,注释就花了。

解决办法是在导入/编译时明确指定 UTF-8。例如命令行导入可以带上编码参数,Studio 的 “Tools → Import” 里也能选择文件编码。关键是导入时选对编码,一旦导入后再去“转码”,整个例程的哈希和编译时间都会被牵连,改动很小但影响面很大。

全局变量(Global)层面相对省心,因为 IRIS 内部字符串就是 Unicode,存进去就是原文。但要注意全局在创建时的“默认字符集”(Collation)——如果是旧库,全局的排序规则可能带 GBK 序,导致报表排序看着乱。这类“乱”跟终端无关,属于排序规则问题,在管理门户的 Globals 页面可以看到每个全局的 Collation 设置。真要改,代价不小,建议先确认业务是否真的受影响,再决定动还是不动。

4. 像“乱码”却不完全是“乱码”的几种误诊场景

终端乱码修多了之后,你会发现有一类问题长得像乱码,实际根子不在终端链路上。不提前把这类区分开,容易白折腾半天。

4.1 日志文件、导出文件、后台作业的“乱码”

IRIS 会往系统里写不少日志,messages.log、作业日志、后台任务输出,都可能夹着中文。终端下type日志文件时看到乱码,不代表 IRIS 终端有问题,而是文件本身的编码和当前终端不匹配。比如messages.log在 Windows 服务器上常按 GBK 写,你用 UTF-8 终端去看自然乱。

我的处理习惯是:先把文件用十六进制查看工具确认开头字节,再确定该用什么代码页打开。file 文件.log在 Linux 下能给出编码猜测,Windows 下可以用 Notepad++ 或 VSCode 右下角的“重新打开方式”快速切换编码。凡是文件场景,别在 IRIS 终端里死磕,退出终端用系统工具看。

后台作业也类似。你用JOB启动了一个任务,任务里写中文日志,这个日志不是写到终端,而是写到设备或文件。最终在哪里看、乱不乱,完全由那个文件/设备的编码决定。如果作业直接继承你的终端设备,那它继承的其实是作业启动那一刻的设备编码,和当前终端可能已经不一致。

4.2 ODBC/JDBC 连接乱码,和终端理论上是两套体系

很多人搜索“IRIS 数据库终端乱码”时,实际遇到的问题是从 ODBC 驱动查询数据乱码。这两个虽然都叫乱码,但机制不同。

终端乱码发生在“I/O 设备”层,ODBC/JDBC 乱码发生在驱动层,主要看 DSN 或连接串里怎么声明字符编码。比如 Caché/IRIS 的 ODBC 驱动在 DSN 配置里有字符集选项,常见值Unicode、UTF-8或GBK。你用原来的系统 DSN 连接,驱动默认按旧编码取数,而查询工具(Excel、PowerBI、报表系统)按 UTF-8 解释,就会出现乱码。

排查思路是:写一个小程序用 ODBC 读取同一条记录,分别在 DSN 编码改成 Unicode/GBK 后各测一次,看哪个组合能让程序输出正确中文。如果 DSN 层面解决不了,再看连接串里的charset参数。这一层与终端没直接关系,但我见过太多人因为终端乱码顺手把 DSN 全改了,结果数据写入时编码也变了,引发更大的事故。改 DSN 之前,请务必先备份原有 DSN 配置。

4.3 第三方数据库工具和 IDE 的编码视角

围绕 IRIS 生态,还有一批外部工具,比如 dbx、各种数据库管理工具、VSCode 的 IRIS 插件、Studio。你会发现,同一个 IRIS 实例,用官方自带终端中文正常,用 VSCode 插件却乱,或者反过来。

这不是 IRIS 的毛病,而是每个工具在读写 IRIS 时各自带了一套编码偏好。VSCode 主要看两个因素:界面右下角的“文件编码”和连接 IRIS 时插件使用的“会话编码”。Studio 老版本在 Windows 上默认跟随系统代码页,如果你系统代码页是 GBK,写进去的中文到 UTF-8 终端看就是花字。记住一个原则:一个系统体系里,所有客户端工具编码要统一,统一成 UTF-8 是当前最省心的选择。别在一台机器上把 Windows 区域设置改成“中文(简体,中国)”,却把 VSCode 强制切成 UTF-8,又把老 Studio 留在 GBK,这样不打架才怪。

5. 一套可以直接抄的排查顺序和验证清单

最后给一套我实际用的排查顺序。按顺序执行的目的是:先处理马上能见的,再做需要判断的,最后再动服务端全局配置。

5.1 从零到一的修复顺序

第一,确认你用的是哪个 IRIS 版本。版本不同,终端客户端的菜单位置、系统方法都可能变化。用write $zv查一下,记下来。

第二,在当前终端里输入并执行:

write "中文测试"

这一步把“终端显示是否正常”这个变量隔离出来。如果这里就乱,先切客户端代码页;如果正常,进入下一步。

第三,检查操作系统层编码。Windows 跑chcp,Linux 跑locale,确认都是 UTF-8 体系。如果发现是 GBK,临时改成 UTF-8 再测。

第四,重启一次 IRIS 终端会话。很多东西在会话建立时就会固化,中断后重新连接,配置才会重新加载。三层客户端改完之后,这一步能验证改动是否真的生效。

第五,如果还乱,进管理门户看 Terminal Settings,把字符集改成 UTF-8,终端类型按实际情况选VT220或ANSI。改完重启终端进程,再测write "中文测试"。

第六,如果是历史老库,测一下 SQL 查询里的中文,例如:

SELECT TOP 5 中文列 FROM 表 WHERE 中文列 IS NOT NULL

SQL 层面正常,终端层面正常,那问题一定在某个你没注意的中间会话上,按第 2 节的终端复用/telnet 场景再查一圈。

5.2 长线稳定运行:统一 UTF-8 的约定

一次乱码修好后,我最想强调的不是“命令”,而是“约定”。你要是让公司内部一半 Windows 机器用 GBK、一半用 UTF-8,那么换了台电脑就乱一次,没完没了。

比较省心的做法是:所有新建命名空间、新建全局时选 UTF-8 作为默认字符集;所有新开发项目的源码文件统一 UTF-8;所有文档里明确写出“连接 IRIS 时,客户端终端编码必须为 UTF-8”;DBA 在提供 ODBC 连接串时同样固定charset=UTF-8或 Unicode。老库的存量全局不轻易转编码,因为重建排序和全局映射的成本很高。你可以在应用层做一个转码工具,需要迁移时平稳地把旧编码数据导成 UTF-8 新存储,而不是在生产库上直接改全局设置,否则一旦索引重建失败,回滚脚本都没有。

5.3 修复后的验证与个人小心得

修复后别只测一个字符,要测三种:中文、标点符号、特殊符号。中文用“百家姓/医院名称”这类实际业务数据,标点用全角逗号、顿号、括号,特殊符号用 Emoji 或生僻字。这三个能同时显示正常,说明从存储到显示整条链路没有丢字节,基本可以收工。

我在实际维护中踩得最多的坑,是那种“今天好好的,明天突然乱”的情况。后来发现,很多是因为有人改了操作系统的“区域和语言”设置,把系统代码页从 UTF-8 调回了 GBK。操作系统这一层一动,IRIS 自带终端、Studio、ODBC 的默认行为全跟着变。所以每次莫名其妙乱码,我第一反应已经不再猜 IRIS,而是先问一句:“这台机器最近有没有动过区域设置”。很多时候,答案就是从这句开始的。

到这儿,该说的都说得差不多了。如果你公司里还是老旧的 Caché 实例,方案基本也一样,只是界面上“Terminal”改成了“Console”,方法名和菜单位置略有出入。花半小时把客户端和服务端编码对齐到 UTF-8,比你以后每次开终端都要祈祷不乱码,值得得多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询