数据库存了些中文字符, 比如'处理脚本'这样的汉字, 结果导致一个python程序报错. 下面记录处理过程和相关结论.

===========================
dal.py 程序片段,python 2.7,
使用了pypyodbc模块
===========================
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

def save(field_value):
    #logger.debug('%s'%type(field_value)) # trouble shooting  时加入的代码
    logger.debug('%s'%field_value)
    save_to_db(field_value)

上面这个程序, 当field_value是汉字时, 报错:
logger.debug报错, UnicodeDecodeError: 'utf8' codec can't decode byte 0xb4 in position 0: invalid start byte

===========================
原因分析:
===========================
我在logger.debug('%s'%field_value), 增加了如下代码, 发现field_value的类型是str, 非unicode.
logger.debug('%s'%type(field_value))

通过type(field_value)获知, field_value本身是str, 而不是unicode. 原因是field_value的值是在pypyodbc模块中初始化的, 并没有做自动做unicode转换.
在我们的py程序中, 表达式'%s'%field_value将实例化一个字符串,因为加了import unicode_literals, 默认是字符串变量将是unicode.
对于非unicode的field_value, python会自动按照utf-8做decode, 而实际上在DB中是按照GBK做的编码, 导致decode会报错.  
那为什么python会自作主张按照utf-8做decode呢? 我原以为是"# -*- coding: utf-8 -*-"和py文件按照utf-8存储, 经试验, 推翻了我的猜测. 有知道的朋友, 请告知.

===========================
测试了几个方法:
===========================
方法1:
  将__future__ 的unicode_literals 拿掉后, logger中汉字显示是乱码, 但save()函数最终存到DB中的汉字, 却没有问题.
方法2:
  将logger.debug('%s'%field_value)   换成 logger.debug(field_value), 不报错, 但logger中汉字显示是乱码
方法3:
  从DB中取出汉字后, 马上对其按GBK 做decode, 将其转成unicode类型, 然后再调用save()方法, 问题彻底解决了.
  field_value=field_value_raw.decode('GBK')  # here field_value is unicode

===========================
知识点:
===========================
1. unicode是一个编码字符集, 即为每个字符设定了一个对应的编码表, 至于如何存储字符的编码, 并没有做规定.  utf-8/utf-16等编码即是unicode的具体存储实现方式, 其中utf-8也是最常用的方式.
2. GB2312、GBK、 GB18030既是编码字符集, 也是存储方式.
3. 如果py文件加了# -*- coding: utf-8 -*-, 字符串默认将以utf-8编码存储, 而且Eclipse也很智能将文件也按照UTF-8存放.
4. 如果py文件加了from __future__ import unicode_literals, 本py文件中声明的字符串将按照unicode 类型.  
5. 对于py程序从DB取出汉字的过程, 涉及到两个不同世界的存储方式, 一般都需要先做decode, 将其转为unicode.
6. 如果使用的是Oracle数据库, 汉字若存在varchar字段, 要看NLS_CHARACTERSET设定值, 比如ZHS16GBK, 需要做decode('GBK');  如果汉字存在NVARCHAR中, 要看 NLS_NCHAR_CHARACTERSET 的设定, 因为NLS_NCHAR_CHARACTERSET多设定为UTF8, python程序就不需要做转换了.

===========================
延伸阅读:
===========================
如joel所讲, 每个开发人员都应该清楚unicode和char set知识, 推荐阮一峰的文章:
http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html
http://www.pythonclub.org/python-basic/encode-detail

字体编辑用中日韩汉字Unicode编码表
http://www.chi2ko.com/tool/CJK.htm

SO上unicode_literals的问答
http://stackoverflow.com/questions/809796/any-gotchas-using-unicode-literals-in-python-2-6

UnicodeDecodeError: 'utf8' codec can't decode的更多相关文章

  1. flask+sqlite3+echarts2+ajax数据可视化报错:UnicodeDecodeError: 'utf8' codec can't decode byte解决方法

    flask+sqlite3+echarts2+ajax数据可视化报错: UnicodeDecodeError: 'utf8' codec can't decode byte 解决方法: 将 py文件和 ...

  2. UnicodeDecodeError: 'utf8' codec can't decode byte 0xce in position 47: invalid continuation byte

  3. UnicodeDecodeError: 'utf-8' codec can't decode byte 0xce in position 22: invalid continuation byte

    在使用python读取文本文件,一般会这样写: # -*- coding:utf-8 -*- f = open("train.txt", "r", encodi ...

  4. UnicodeDecodeError: 'utf-8' codec can't decode byte 0xce in position 52: invalid continuation byte

    代码: df_w = pd.read_table( r'C:\Users\lab\Desktop\web_list_n.txt', sep=',', header=None) 当我用pandas的re ...

  5. TensorFlow学习笔记(UTF-8 问题解决 UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte)

    我使用VS2013  Python3.5  TensorFlow 1.3  的开发环境 UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff ...

  6. UnicodeDecodeError: 'utf-8' codec can't decode byte 0xef in position 99: invalid continuation byte

    Traceback (most recent call last): File "/Users/c2apple/PycharmProjects/easyToPython/fileMethod ...

  7. 解决在使用gensim.models.word2vec.LineSentence加载语料库时报错 UnicodeDecodeError: 'utf-8' codec can't decode byte......的问题

    在window下使用gemsim.models.word2vec.LineSentence加载中文维基百科语料库(已分词)时报如下错误: UnicodeDecodeError: 'utf-8' cod ...

  8. 用python3读CSV文件,出现UnicodeDecodeError: 'utf-8' codec can't decode byte 0xd0 in position 0: invalid con

    使用pd.read_csv()读csv文件时,出现如下错误: UnicodeDecodeError: ‘utf-8’ codec can’t decode byte 0xd0 in position ...

  9. 解决Requests中文乱码【有用】,读取htm文件 读取txt文件报错:UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc8 in position 0

    打开这个网址https://blog.csdn.net/chaowanghn/article/details/54889835 python在open读取txt文件时,出现UnicodeDecodeE ...

随机推荐

  1. Jenkins邮件扩展插件【Email Extension Plugin】的参数使用

    经过测试,无论在windows还是linux,统一使用参数时,都是按照linux的格式,如:${WORKPASE}

  2. C++开发的基于TCP协议的内网聊天工具

    项目相关地址 源码:https://github.com/easonjim/TCPChat bug提交:https://github.com/easonjim/TCPChat/issues

  3. oracle11g dataguard 安装手册(转)

    文章转自:http://www.cnblogs.com/tippoint/archive/2013/04/18/3029019.html 一.前言:   网络上关于dataguard的配置文章很多,但 ...

  4. phpize报cannot find autoconf

    突然想往php种增加个模块,可是又不想重新编译php,因为真的比较费时间. phpize就可以解决这个问题. 遇到的问题: Configuring for: PHP Api Version: Zend ...

  5. [NOIP2013] 提高组 洛谷P1969 积木大赛

    题目描述 春春幼儿园举办了一年一度的“积木大赛”.今年比赛的内容是搭建一座宽度为n的大厦,大厦可以看成由n块宽度为1的积木组成,第i块积木的最终高度需要是hi. 在搭建开始之前,没有任何积木(可以看成 ...

  6. Windows网络驱动、NDIS驱动(微端口驱动、中间层驱动、协议驱动)、TDI驱动(网络传输层过滤)、WFP(Windows Filtering Platform)

    catalog . 引言 . Windows 2000网络结构和OSI模型 . NDIS驱动 . NDIS微端口驱动编程实例 . NDIS中间层驱动编程实例 . NDIS协议层驱动编程实例 . TDI ...

  7. hdu 2014 青年歌手大奖赛_评委会打分

    题意: 输入N个数,去掉最大和最小的数,求剩余的数的平均数. 解法: 找到分别最大和最小的数,然后从总和中减去他们,再求平均数(不要排序): 1: #include<stdlib.h> 2 ...

  8. global--命名空间的使用(一些零散的js方法)

    var GLOBAL = {}; GLOBAL.namespace = function (str) { var arr = str.split('.'), o = GLOBAL; for (var ...

  9. OpenGLES入门笔记一

    学习地址:http://www.raywenderlich.com/3664/opengl-tutorial-for-ios-opengl-es-2-0 中文翻译:http://www.cnblogs ...

  10. POJ 2942Knights of the Round Table(二分图判定+双连通分量)

    题目链接 题意:一些骑士,他们有些人之间有矛盾,现在要求选出一些骑士围成一圈,圈要满足如下条件:1.人数大于1.2.总人数为奇数.3.有仇恨的骑士不能挨着坐.问有几个骑士不能和任何人形成任何的圆圈. ...