我使用sqlalchemy查询MySQL数据库并收到以下错误:
UnicodeDecodeError: 'utf8' codec can't decode bytes in position 498-499: unexpected end of data
表中的一列定义为Unicode(500)
,因此此错误向我建议有一个被截断的条目,因为它超过500个字符。有没有办法处理此错误仍然加载条目?有没有办法找到错误的条目并删除它除了尝试逐个(或批量)加载每个条目,直到我收到错误?
答案 0 :(得分:3)
简而言之,你应该改变:
Unicode(500)
为:
Unicode(500, unicode_errors='ignore', convert_unicode='force')
(Python 2代码如下,但原则在python 3中保存;只有部分输出会有所不同。)
当你解码一个bytestring时,它会抱怨如果无法解码bytestring,你会看到错误。
>>> u = u'ABCDEFGH\N{TRADE MARK SIGN}'
>>> u
u'ABCDEFGH\u2122'
>>> print(u)
ABCDEFGH™
>>> s = u.encode('utf-8')
>>> s
'ABCDEFGH\xe2\x84\xa2'
>>> truncated = s[:-1]
>>> truncated
'ABCDEFGH\xe2\x84'
>>> truncated.decode('utf-8')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/cliffdyer/.virtualenvs/edx-platform/lib/python2.7/encodings/utf_8.py",
line 16, in decode
return codecs.utf_8_decode(input, errors, True)
UnicodeDecodeError: 'utf8' codec can't decode bytes in position 8-9: unexpected
end of data
Python提供了处理解码错误的不同可选模式。提出异常是默认设置,但您也可以截断文本或将字符串的格式错误的部分转换为官方的unicode替换字符。
>>> trunc.decode('utf-8', errors='replace')
u'ABCDEFGH\ufffd'
>>> trunc.decode('utf-8', errors='ignore')
u'ABCDEFGH'
这正是列处理中发生的事情。
查看sqlalchemy/sql/sqltypes.py中的Unicode和String类,看起来有一个unicode_errors
参数可以传递给构造函数,构造函数将其值传递给编码器的errors参数。还需要注意,您需要设置convert_unicode='force'
才能使其正常运行。
因此Unicode(500, unicode_errors='ignore', convert_unicode='force')
可以解决您的问题,如果您可以截断数据的末尾。
如果您对数据库有一定的控制权,那么通过定义数据库以使用utf8mb4
字符集,您应该能够在将来防止此问题。 (不要只使用utf8
,否则它将在四个字节的utf8字符上失败,包括大多数表情符号)。然后,您将保证在您的数据库中存储和返回有效的utf-8。
答案 1 :(得分:0)
将要存储的列设为BLOB
。加载数据后,请执行各种操作,例如
SELECT MAX(LENGTH(col)) FROM ... -- to see what the longest is in _bytes_.
将数据复制到另一个BLOB
列并执行
ALTER TABLE t MODIFY col2 TEXT CHARACTER SET utf8 ... -- to see if it converts correctly
如果成功,那么
SELECT MAX(CHAR_LENGTH(col2)) ... -- to see if the longest is more than 500 _characters_.
在你尝试了类似的东西后,我们可以看到接下来要采取的方向。
答案 2 :(得分:0)
简而言之,您的MySQL设置不正确,因为它会在中间序列中截断UTF-8字符。我会检查两次MySQL实际上期望在会话和表本身中使用UTF-8的字符编码。
我建议切换到PostgreSQL(认真)以避免这种问题:PostgreSQL不仅在默认配置中正确理解UTF-8,而且它也不会截断字符串以适应值,选择提高而是一个错误:
psql (9.5.3, server 9.5.3)
Type "help" for help.
testdb=> create table foo(bar varchar(4));
CREATE TABLE
testdb=> insert into foo values ('aaaaa');
ERROR: value too long for type character varying(4)
这也与Python的Zen不同:
明确比隐含更好。
和
错误不应该默默地传递。
除非明确沉默。
面对模棱两可,拒绝猜测的诱惑。