情景:需要读取外部文件的信息,包括文件名、文件内容,如果都是英文、都是utf-8编码那就啥烦恼都没有了,现在的情况就是文件名会出现中文,文件内容也会出现中文并且编码还不一定是utf-8。
django表现:如果文件名包含中文,从后台传递到templates时会直接报错,如:DjangoUnicodeDecodeError: ‘utf8’ codec can’t decode…所以我们需要玩转python的编码(encode)与解码(decode)。
在文章的开始,还是推荐先看看这篇文章:
https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001431664106267f12e9bef7ee14cf6a8776a479bdec9b9000
我把最重点的摘出来:
1、我们最常接触到的编码有四种:Unicode、ASCII、UTF-8、GB2312;
2、在计算机内存中,统一使用Unicode编码;
3、用记事本编辑的时候,从文件读取的UTF-8(GB2312/ASCII)字符被转换为Unicode字符到内存里,编辑完成后,保存的时候再把Unicode转换为UTF-8(GB2312/ASCII)保存到文件;
4、如果要在网络上传输,或者保存到磁盘上,就需要把python字符串str变为以字节为单位的bytes,以Unicode表示的str通过encode()方法可以编码为指定的bytes;
5、反过来,如果我们从网络或磁盘上读取了字节流,那么读到的数据就是bytes。要把bytes变为str,就需要用decode()方法。
顺便借用一下原图:
从上面可知,有两个最重要的函数encode() 与 decode()。这时,我们都会想到:如何知道一个文件是使用何种编码格式呢?不用担心,python都替我们做好了:
import chardet
with open(sql_file, "r") as f:
file_content = "".join(f.readlines())
print chardet.detect(sql_file_content)
# 输出一个dict类型数据,我们只需关注 encoding 项:
# {'confidence': 0.99, 'language': 'Chinese', 'encoding': 'GB2312'}
开始解决我们的问题,现假设有一个中文文件:kbssoptsett_期权系统修改营业部信息4300.sql,内容不确实是不是utf-8编码,怎么保证程序能顺利解决各种情况,把文件名与文件内容展示到前端。
在django整个项目中,默认的编码都是utf-8,所以我们要做就是在把文件读入内存时,正确的解码即可,剩下的django都会帮我们搞掂。
对于文件名,因为带中文,我们直接使用:
# 这样就可以把文件名正常读入内存,
file_name = file_name.decode("gb2312")
而对于文件内容,我们首先需要判断文件的编码格式是什么,如果是utf-8,那如果使用decode(“gb2312”),就会报错,而如果是gb2312,不进行decode(),到时内容也无法解析,(gb2312基本都可以解析中文),所以完整的是:
with open(sql_file, "r") as f:
# 先读取文件内容
sql_file_content = "".join(f.readlines())
# 只要不是 utf-8编码,一率用 gb2312 解码
if chardet.detect(sql_file_content)["encoding"] != "utf-8":
sql_file_content = sql_file_content.decode("gb2312")
前端最终效果图: