解决一个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
研究过程
- 检查locale:每一台locale一样
- 检查JVM:
-Dfile.encoding=UTF-8一样 - 检查
/proc/<pid>/environ:LANG不一样 - 解决,在JVM进程的环境变量中
export LANG=en_US.UTF-8解决。
反思
- LANG 按理说完全不影响Java
- 已经2062年了不会存在
Charset.defaultCharset收到环境变量的问题 - 初学者都知道编译和运行环境都有
file.encoding=UTF-8 - 作为高级工程师,并不会忘记给 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的时候,发生回退了。

浙公网安备 33010602011771号