解决Oracle11g的SQL Loader(sqlldr)命令行中文乱码问题

文章讲述了在Linux环境下使用Oracle11g的SQLLoader出现命令行输出乱码的问题,分析了NLS_LANG环境变量对字符集的影响,以及客户端设置与服务器字符集的一致性需求。通过将NLS_LANG的语言部分改为英文,解决了乱码显示,同时提醒了更改操作系统字符集的潜在风险。
摘要由CSDN通过智能技术生成

结论:

Oracle 11g 的 SQL Loader(sqlldr)命令行输出的语言和字符集受到NLS_LANG环境变量控制。
比如:NLS_LANG=SIMPLIFIED CHINESE_CHINA.ZHS16GBK表示使用简体中文语言和GBK编码。

有兴趣可以继续看下面啰嗦的分析过程内容。

(一)现象

程序在Linux下调用sqlldr时,发现其返回的命令行内容存在乱码。
手动测试sqlldr命令,果然和程序读到的一样,是乱码。
仔细检查发现是GBK格式,因为Linux下基本都默认UTF8编码,所以直接终端显示就变乱码了。

$shion@shionwsl ~> sqlldr

SQL*Loader: Release 11.2.0.4.0 - Production on ������ 4�� 27 09:08:30 2023
Copyright (c) 1982, 2011, Oracle and/or its affiliates.  All rights reserved.

�÷�: SQLLDR keyword=value [,keyword=value,...]

��Ч�Ĺؼ���:

    userid -- ORACLE �û���/����
   control -- �����ļ���
       log -- ��־�ļ���
       bad -- �����ļ���
      data -- �����ļ���
   discard -- �����ļ���
   ......

回到Windows下调用同版本sqlldr,正常显示:

PS C:\Users\Shion> sqlldr

SQL*Loader: Release 11.2.0.4.0 - Production on 星期四 427 09:11:50 2023
Copyright (c) 1982, 2011, Oracle and/or its affiliates.  All rights reserved.

用法: SQLLDR keyword=value [,keyword=value,...]

有效的关键字:

    userid -- ORACLE 用户名/口令
   control -- 控制文件名
       log -- 日志文件名
       bad -- 错误文件名
      data -- 数据文件名
   discard -- 废弃文件名
   ......

(二)分析

(2.1)入库文件字符集?(No)

我们都知道,文件内容如果带有中文是有编码的,所以调用sqlldr入库时,需要指定其编码。
这部分在控制文件.ctl中完成。
如下例,指定了ZHS16GBK 编码方式:

OPTIONS (skip=0) LOAD DATA CHARACTERSET ZHS16GBK 
INFILE 'xxxxx/eps.txt' 
APPEND INTO TABLE yyyyy 
FIELDS TERMINATED BY X'09' 
TRAILING NULLCOLS 
(xxxx char(16),yyyy,zzzz,......)

会不会因为导入的文件都是GBK编码影响了sqlldr的命令行输出呢?当然不是!!!
因为我们只输入了sqlldr命令本身,没有任何参数,中文已经是乱码了。

(2.2)客户端设置?(Yes)

既然Windows和Linux都输出GBK,而不是尊重操作系统的字符集(编码)……
那么是不是因为同样的客户端设置引起的呢?
两边都设置了:

NLS_LANG=SIMPLIFIED CHINESE_CHINA.ZHS16GBK

尝试将Linux那边改为SIMPLIFIED CHINESE_CHINA.AL32UTF8
再调用sqlldr,果然没有乱码了。但 问题并没有解决!!!

因为Oracle客户端设置是需要和服务端一致的,既然服务端是GBK而客户端改为了UTF8,会导致你用SQL选出的中文变成乱码。这是Oracle一个很神奇的设置,它完全不考虑你需要同时连接2个不同字符集服务端的情况。Java已经不再读这个客户端配置,但也引发了其它的问题(之前有遇到过并记录到了文章)。

那怎么办呢?

(2.3)分析NLS_LANG设置

我们来看一下(当然还有很多其它国家和语言/字符集设置):

NLS_LANG=SIMPLIFIED CHINESE_CHINA.ZHS16GBK
NLS_LANG=JAPANESE_JAPAN.AL32UTF8
NLS_LANG=AMERICAN_AMERICA.WE8ISO8859P15
......

NLS_LANG的值,明显分为两部分:
中间用点连接,格式为:NLS_LANG=语言_国家 . 字符集

  1. 语言和国家
  2. 字符集(编码方式)

现在的问题是:

  • sqlldr的命令行显示,不尊重操作系统字符集,而是采用了NLS_LANG的字符集
  • 这个客户端的字符集设置又必须和服务端一致不能随便改。
  • Linux操作系统字符集是UTF8和ORACLE客户端字符集GBK不一样,导致冲突。

所以?改Linux操作系统字符集?当然不能!!!
随便改操作系统字符集,无异于单表有乱码改整个数据库字符集!!!
在生产系统中毫不考虑还其它程序在跑,⚠️属于破坏行为。
量刑标准我不清楚,同时一般人权限也不够。

(三)解决(无奈)

由于Oracle自身的设定的原因,通常情况下Linux的UTF8和Oracle服务端要求的GBK编码一定冲突。
用程序读取很简单,创建流读取命令行输出信息时,指定成NLS_LANG同样的编码就OK了。

但是人敲命令行怎么办呢???
只能看乱码么,还是每次设法转成看GBK?

刚才提到了既然分两部分,第二部分不能改,就只能看第一部分了,也就是语言_国家设置。
那就只能把语言改为任何编码下都能正常显示的语言:英语了。

NLS_LANG=AMERICAN_AMERICA.ZHS16GBK

谁说米国人不能说中文呢?
设置后如下,同时还解决了翻译成中文后看不懂的问题(手动狗头)。

$shion@shionwsl ~> sqlldr

SQL*Loader: Release 11.2.0.4.0 - Production on Thu Apr 27 10:01:24 2023
Copyright (c) 1982, 2011, Oracle and/or its affiliates.  All rights reserved.

Usage: SQLLDR keyword=value [,keyword=value,...]

Valid Keywords:

    userid -- ORACLE username/password
   control -- control file name
       log -- log file name
       bad -- bad file name
      data -- data file name
   discard -- discard file name
   ......
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值