Python抽取Oracle数据库多字节字符时编码异常的解决问询
问题描述
从Oracle数据库抽取数据导出至CSV文件时遇到编码相关问题:
- 使用默认UTF-8编码时,抛出错误:
'utf-8' codec can't decode byte 0xd1 in position 14: invalid continuation byte - 数据库字符集为AL32UTF8,国家字符集为AL16UTF8,部分西班牙文
ñ字符被替换为? - 尝试改用ISO-8859-1编码后,前两个查询可正常运行,但其他查询出现
partial multibyte character错误,仍存在字符被替换为?的情况
解决步骤
- 对齐连接编码与数据库字符集:数据库字符集是AL32UTF8,连接时直接使用
UTF-8编码,同时确保NLS_LANG环境变量与数据库字符集保持一致,避免编码转换冲突。 - 指定国家字符集编码:cx_Oracle连接时额外设置
nencoding="UTF-16",匹配数据库的AL16UTF8国家字符集,确保所有字符类型数据正确读取。 - CSV导出用标准UTF-8:导出时使用
utf-8编码(如需兼容Excel可改用utf-8-sig),避免使用UTF-16这类兼容性较差的编码。
修正后的代码
import os import cx_Oracle import pandas as pd from os.path import exists # 设置NLS_LANG匹配数据库字符集 os.environ['NLS_LANG'] = 'AMERICAN_AMERICA.AL32UTF8' connection = None cursor = None dir_path = './csv_files/' queries = { 'file1.csv': "SELECT * FROM table1", 'file2.csv': "SELECT * FROM table2", } if not exists(dir_path): os.makedirs(dir_path) try: dsn_tns = cx_Oracle.makedsn('171.11.1.111', '1521', sid='ñññ') # 连接时指定正确的编码和国家字符集 connection = cx_Oracle.connect( user='your_user', password='your_password', dsn=dsn_tns, encoding="UTF-8", nencoding="UTF-16" ) cursor = connection.cursor() for file_name, query in queries.items(): try: cursor.execute(query) rows = cursor.fetchall() columns = [col[0] for col in cursor.description] df = pd.DataFrame(rows, columns=columns) file_path = os.path.join(dir_path, file_name) # 使用UTF-8导出,兼容Excel可替换为'utf-8-sig' df.to_csv(file_path, index=False, encoding='utf-8', errors='strict') except Exception as e: print(f"处理{file_name}时出错: {e}") continue except Exception as e: print(f"连接数据库出错: {e}") finally: if cursor: cursor.close() if connection: connection.close()
关键注意点
encoding和nencoding必须分别匹配数据库的字符集和国家字符集,确保Python与Oracle之间的字符传递无转换损耗。- 导出时使用
errors='strict'可以及时发现未处理的编码异常,便于排查问题,而非直接替换为?掩盖错误。
内容的提问来源于stack exchange,提问作者SydVega
相关产品推荐
相关产品推荐

