无法使用cx_Oracle编写Unicode文本

时间:2016-06-01 16:55:41

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

我正在编写一个读取CSV的Python脚本,使用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环境变量设置为每this post .AL16UTF16_.AL16UTF16AMERICAN_AMERICA.WE8MSWIN1252之类的内容,但我仍然可以同样的错误。

鉴于我正在读取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模块是我正在研究的数据抽象库。负责写入Oracle表的函数位于here

完整的追溯是:

  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)

1 个答案:

答案 0 :(得分:1)

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

请注意,如果NLS_LANG的值无效,则基本上会被忽略。 AL16UTF16就是这样一个无效的条目!因此,将其设置为您想要的值(例如.UTF8)并检查连接上的编码和编码值,直到获得所需的值。

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