【问题标题】:Can't write Unicode text using cx_Oracle无法使用 cx_Oracle 编写 Unicode 文本
【发布时间】:2016-10-01 04:11:48
【问题描述】:

我正在编写一个 Python 脚本,该脚本读取 CSV 并使用 cx_Oracle 将内容写入 Oracle 数据库。到目前为止,我一直收到以下错误:

UnicodeEncodeError: 'ascii' codec can't encode character '\xa0' in position 1369: ordinal not in range(128)

显然,cx_Oracle 正在尝试将 Unicode 字符转换为 ASCII,但它不起作用。

几个澄清点:

  • 我使用的是 Python 3.4.3
  • CSV 文件以 UTF-8 编码,打开方式类似于 open('all.csv', encoding='utf8')
  • 我在数据库中使用NVARCHAR2 字段作为文本,NLS_NCHAR_CHARACTERSET 设置为AL16UTF16NLS_CHARACTERSETWE8MSWIN1252,但据我了解,这不相关,因为我使用的是 NVARCHAR2
  • 我尝试将NLS_LANG 环境变量设置为.AL16UTF16_.AL16UTF16AMERICAN_AMERICA.WE8MSWIN1252this post,但我仍然遇到同样的错误。

鉴于我正在读取 UTF-8 文件并尝试写入 Unicode 编码表,任何人都可以想到为什么 cx_Oracle 仍会尝试将我的数据转换为 ASCII?

我可以使用此代码产生错误:

field_map = {
    ...
}

with open('all.csv', encoding='utf8') as f:
    reader = csv.DictReader(f)
    out_rows = []

    for row in reader:
        if i == 1000:
            break

        out_row = {}
        for field, source_field in field_map.items():
            out_val = row[source_field]            
            out_row[field] = out_val

        out_rows.append(out_row)

        i += 1

out_db = datum.connect('oracle-stgeom://user:pass@db')
out_table = out_db['service_requests']
out_table.write(out_rows, chunk_size=10000)

datum 模块是我正在开发的一个数据抽象库。在here找到负责写入Oracle表的函数。

完整的回溯是:

  File "C:\Projects\311\write.py", line 64, in <module>
    out_table.write(out_rows, chunk_size=10000)
  File "z:\datum\datum\table.py", line 89, in write
    self._child.write(rows, from_srid=from_srid, chunk_size=chunk_size)
  File "z:\datum\datum\oracle_stgeom\table.py", line 476, in write
    self._c.executemany(None, val_rows)
UnicodeEncodeError: 'ascii' codec can't encode character '\xa0' in position 1361: ordinal not in range(128)

【问题讨论】:

  • 你能提供完整的追溯吗?至少您正在使用的代码的相关部分? cx_Oracle 完全有能力将 Unicode 文本写入数据库!
  • @AnthonyTuinga 我已经添加了一些代码和回溯,在此先感谢!

标签: python oracle unicode utf-8 cx-oracle


【解决方案1】:

检查连接上“encoding”和“nencoding”属性的值。该值是通过调用检查环境变量 NLS_LANG 和 NLS_NCHAR 的 OCI 例程来设置的。看起来这个值是 US-ASCII 或等效的。写入数据库时​​,cx_Oracle 获取文本并通过以 Oracle 客户端期望的编码进行编码来获取字节字符串。请注意,这与数据库编码无关。一般来说,为了获得最佳性能,最好匹配数据库和客户端编码——但如果你不这样做,Oracle 会很乐意在两者之间进行转换,前提是所有使用的字符都可以在两个字符集中表示!

请注意,如果 NLS_LANG 的值无效,它实际上会被忽略。 AL16UTF16 就是这样一个无效条目!所以把它设置成你想要的值(比如.AL32UTF8)并检查连接上的encoding和nencoding的值,直到你得到你想要的。

另外请注意,除非您另有说明,否则所有通过 cx_Oracle 绑定到数据库的字符串都被假定为正常编码,而不是 NCHAR 编码。您可以通过使用 cursor.setinputsizes() 并指定输入类型为 NCHAR、FIXED_NCHAR 或 LONG_NCHAR 来覆盖它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-05-17
    • 2014-12-06
    • 2015-08-19
    • 2016-05-01
    • 1970-01-01
    • 2017-09-28
    • 2016-12-01
    • 2013-03-02
    相关资源
    最近更新 更多