尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Caché/IRIS终端中文乱码排查与修复:从编码对齐到UTF-8配置

Caché/IRIS终端中文乱码排查与修复:从编码对齐到UTF-8配置 先交代一下背景。我在一家做医疗信息化的公司干了六七年项目里跑的基本都是 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 $zvwrite t是验证写出去能不能原样读出来。$zv显示的是 IRIS 版本如果版本信息这种纯英文都正常说明链路至少没坏到完全不通。接着再跑write $system.Process.Version()然后退出终端在操作系统命令行里看一下当前环境的编码。Windows 下用chcpLinux 下用locale。这一步最容易被忽略但它几乎是所有乱码的共同起点。要是终端里write t正常但一旦执行do ^%SYSTEM这种菜单程序就乱问题大概率在终端类型定义和字符集设置上不是编码翻译而是“终端能力协商”出问题。后面第 3 节会展开说。2. 客户端环境这层最容易改完就见效如果你只是急着把眼前这坨乱码弄正常我建议从客户端开始改。因为服务端配置通常已经固化在你公司的维护脚本里而客户端是你马上就能动手的部分。2.1 Windows 自带终端代码页、字体、新版终端三层分别处理Windows 下最经典的做法是切换代码页。在 CMD 里执行chcp 65001这会告诉控制台“接下来请用 UTF-8 解释字节流”。打完再重新启动 IRIS 终端注意要先退出再重新进来同一个进程里切换有时不彻底大部分中文就能恢复正常。如果你以前习惯用chcp 936GBK而在 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/localeCentOS/RHEL 类写入/etc/locale.conf临时测试就用export LANGzh_CN.UTF-8验证当前会话。这里要专门提一下终端复用工具和第三方终端比如tmux、screen、Tabby 这类。它们本身不是编码问题制造者但会“继承”输入终端的编码设置。如果你在 Windows 上的 Tabby 里用 UTF-8 连到 LinuxLinux 系统的LANG却是 GBKTabby 会很听话地把 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 跑chcpLinux 跑locale确认都是 UTF-8 体系。如果发现是 GBK临时改成 UTF-8 再测。第四重启一次 IRIS 终端会话。很多东西在会话建立时就会固化中断后重新连接配置才会重新加载。三层客户端改完之后这一步能验证改动是否真的生效。第五如果还乱进管理门户看 Terminal Settings把字符集改成 UTF-8终端类型按实际情况选VT220或ANSI。改完重启终端进程再测write 中文测试。第六如果是历史老库测一下 SQL 查询里的中文例如SELECT TOP 5 中文列 FROM 表 WHERE 中文列 IS NOT NULLSQL 层面正常终端层面正常那问题一定在某个你没注意的中间会话上按第 2 节的终端复用/telnet 场景再查一圈。5.2 长线稳定运行统一 UTF-8 的约定一次乱码修好后我最想强调的不是“命令”而是“约定”。你要是让公司内部一半 Windows 机器用 GBK、一半用 UTF-8那么换了台电脑就乱一次没完没了。比较省心的做法是所有新建命名空间、新建全局时选 UTF-8 作为默认字符集所有新开发项目的源码文件统一 UTF-8所有文档里明确写出“连接 IRIS 时客户端终端编码必须为 UTF-8”DBA 在提供 ODBC 连接串时同样固定charsetUTF-8或 Unicode。老库的存量全局不轻易转编码因为重建排序和全局映射的成本很高。你可以在应用层做一个转码工具需要迁移时平稳地把旧编码数据导成 UTF-8 新存储而不是在生产库上直接改全局设置否则一旦索引重建失败回滚脚本都没有。5.3 修复后的验证与个人小心得修复后别只测一个字符要测三种中文、标点符号、特殊符号。中文用“百家姓/医院名称”这类实际业务数据标点用全角逗号、顿号、括号特殊符号用 Emoji 或生僻字。这三个能同时显示正常说明从存储到显示整条链路没有丢字节基本可以收工。我在实际维护中踩得最多的坑是那种“今天好好的明天突然乱”的情况。后来发现很多是因为有人改了操作系统的“区域和语言”设置把系统代码页从 UTF-8 调回了 GBK。操作系统这一层一动IRIS 自带终端、Studio、ODBC 的默认行为全跟着变。所以每次莫名其妙乱码我第一反应已经不再猜 IRIS而是先问一句“这台机器最近有没有动过区域设置”。很多时候答案就是从这句开始的。到这儿该说的都说得差不多了。如果你公司里还是老旧的 Caché 实例方案基本也一样只是界面上“Terminal”改成了“Console”方法名和菜单位置略有出入。花半小时把客户端和服务端编码对齐到 UTF-8比你以后每次开终端都要祈祷不乱码值得得多。
返回列表