解决一个LANG引起beeline导出中文乱码的问题

问题

机缘巧合下,两台一模一样的 Linux (Centos)locale=zh_CN.UTF-8,出现 Java 调用 beeline 输出csv乱码。

这源自一起生产环境用户反馈的故障。

分析

设置不同的 LANG 调用 beeline 查看输出结果:

=== LANG=zh_CN.UTF-8 输出 ===
_u1.id,_u1.name,_u1.status,_u1.query_date
??????ID,????????????,????????????,2026-03-04
001,??????,??????,2026-03-04
002,??????,??????,2026-03-04

=== LANG=en_US.UTF-8 输出 ===
_u1.id,_u1.name,_u1.status,_u1.query_date
测试ID,测试名称,正常状态,2026-03-04
001,张三,在线,2026-03-04
002,李四,离线,2026-03-04

=== LANG=C.UTF-8 输出 ===
_u1.id,_u1.name,_u1.status,_u1.query_date
测试ID,测试名称,正常状态,2026-03-04
001,张三,在线,2026-03-04
002,李四,离线,2026-03-04

=== 检查文件编码 ===
/tmp/test_zh_cn.csv:  ASCII text
/tmp/test_en_us.csv:  UTF-8 Unicode text
/tmp/test_c_utf8.csv: UTF-8 Unicode text

研究过程

  1. 检查locale:每一台locale一样
  2. 检查JVM:-Dfile.encoding=UTF-8 一样
  3. 检查 /proc/<pid>/environ:LANG不一样
  4. 解决,在JVM进程的环境变量中 export LANG=en_US.UTF-8 解决。

反思

  1. LANG 按理说完全不影响Java
  2. 已经2062年了不会存在 Charset.defaultCharset 收到环境变量的问题
  3. 初学者都知道编译和运行环境都有 file.encoding=UTF-8
  4. 作为高级工程师,并不会忘记给 csv 加 UTF-8 BOM

回过头来再看:
locale 直接输出:

Cannot set LC_ALL to default locale: No such file or directory

虽然明显,但是人们都会忽略不见的吧

locale: Cannot set LC_CTYPE to default locale: No such file or directory
locale: Cannot set LC_MESSAGES to default locale: No such file or directory
locale: Cannot set LC_ALL to default locale: No such file or directory
LANG=zh_CN.UTF-8
LC_CTYPE="zh_CN.UTF-8"
LC_NUMERIC="zh_CN.UTF-8"
LC_TIME="zh_CN.UTF-8"
LC_COLLATE="zh_CN.UTF-8"
LC_MONETARY="zh_CN.UTF-8"
LC_MESSAGES="zh_CN.UTF-8"
LC_PAPER="zh_CN.UTF-8"
LC_NAME="zh_CN.UTF-8"
LC_ADDRESS="zh_CN.UTF-8"
LC_TELEPHONE="zh_CN.UTF-8"
LC_MEASUREMENT="zh_CN.UTF-8"
LC_IDENTIFICATION="zh_CN.UTF-8"
LC_ALL=

结论

locale -a 检查发现,系统没有安装这个 zh_CN.UTF-8 的locale,因此 beeline 或者 Java 进程在某个底层代码里面 set locale的时候,发生回退了。

posted @ 2026-03-07 17:50  一杯半盏  阅读(6)  评论(0)    收藏  举报