增加或改变已打开文件的编码

问题

你想在不关闭一个已打开的文件前提下增加或改变它的 Unicode 编码。

解法

如果你想给一个以二进制模式打开的文件添加 Unicode 编码/解码方式,可以使用io.TextIOWrapper() 对象包装它。比如:

import urllib.request
import io
u = urllib.request.urlopen('http://www.python.org')
f = io.TextIOWrapper(u, encoding='utf-8')
text = f.read()

如果你想修改一个已经打开的文本模式的文件的编码方式,可以先使用 detach()方法移除掉已存在的文本编码层,并使用新的编码方式代替。下面是一个在sys.stdout 上修改编码方式的例子:

>>> import sys
>>> sys.stdout.encoding
'UTF-8'
>>> sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding='latin-1')
>>> sys.stdout.encoding
'latin-1'
>>>

这样做可能会中断你的终端,这里仅仅是为了演示而已。

PS. 我的测试结果

Python 3.9.0 (tags/v3.9.0:9cf6752, Oct  5 2020, 15:34:40) [MSC v.1927 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license()" for more information.
>>> import io,sys
>>> sys.stdout.encoding
'utf-8'
>>> sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding='latin-1')
Traceback (most recent call last):File "<pyshell#2>", line 1, in <module>sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding='latin-1')
io.UnsupportedOperation: detach
>>>

讨论

I/O 系统由一系列的层次构建而成。你可以试着运行下面这个操作一个文本文件的例子来查看这种层次:

>>> f = open('sample.txt','w')
>>> f
<_io.TextIOWrapper name='sample.txt' mode='w' encoding='UTF-8'>
>>> f.buffer
<_io.BufferedWriter name='sample.txt'>
>>> f.buffer.raw
<_io.FileIO name='sample.txt' mode='wb'>
>>>

在这个例子中, io.TextIOWrapper 是一个编码和解码 Unicode 的文本处理层,io.BufferedWriter 是一个处理二进制数据的带缓冲的 I/O 层, io.FileIO 是一个表示操作系统底层文件描述符的原始文件。增加或改变文本编码会涉及增加或改变最上面的 io.TextIOWrapper 层。

一般来讲,像上面例子这样通过访问属性值来直接操作不同的层是很不安全的。例如,如果你试着使用下面这样的技术改变编码看看会发生什么:

>>> f
<_io.TextIOWrapper name='sample.txt' mode='w' encoding='UTF-8'>
>>> f = io.TextIOWrapper(f.buffer, encoding='latin-1')
>>> f
<_io.TextIOWrapper name='sample.txt' encoding='latin-1'>
>>> f.write('Hello')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: I/O operation on closed file.
>>>

detach() 方法会断开文件的最顶层并返回第二层,之后最顶层就没什么用了。例如:

>>> f = open('sample.txt', 'w')
>>> f
<_io.TextIOWrapper name='sample.txt' mode='w' encoding='UTF-8'>
>>> b = f.detach()
>>> b
<_io.BufferedWriter name='sample.txt'>
>>> f.write('hello')
Traceback (most recent call last):File "<stdin>", line 1, in <module>
ValueError: underlying buffer has been detached
>>>

一旦断开最顶层后,你就可以给返回结果添加一个新的最顶层。比如:

>>> f = io.TextIOWrapper(b, encoding='latin-1')
>>> f
<_io.TextIOWrapper name='sample.txt' encoding='latin-1'>
>>>

尽管已经向你演示了改变编码的方法,但是你还可以利用这种技术来改变文件行处理、错误机制以及文件处理的其他方面。例如:

>>> sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding='ascii',
...                                     errors='xmlcharrefreplace')
>>> print('Jalape\u00f1o')
Jalape&#241;o
>>>

注意下最后输出中的非 ASCII 字符 ñ 是如何被 ñ 取代的。

《Python Cookbook 3rd》笔记(5.16):增加或改变已打开文件的编码相关推荐

  1. 《Python Cookbook 3rd》笔记汇总

    文章目录 一.数据结构 二.字符串和文本 三.数字.日期和时间 四.迭代器与生成器 五.文件与IO 一.数据结构 标题 关键词 1.1:拆分序列后赋值给多个变量 可迭代对象.拆分赋值 1.2:拆分任意 ...

  2. 《Python Cookbook 3rd》笔记(1.4):查找最大或最小的N个元素

    <Python Cookbook 3rd>1.4:查找最大或最小的N个元素 问题 怎样从一个集合中获得最大或者最小的N个元素列表? 解法 heapq 模块有两个函数:nlargest()和 ...

  3. 《Python cookbook》笔记二

    <Python cookbook>笔记二 第二章 字符串和文本 -使用多个界定符分割字符串- 你需要将一个字符串分割为多个字段,但是分隔符 (还有周围的空格) 并不是固定 的. # str ...

  4. Machine Learning with Python Cookbook 学习笔记 第8章

    Chapter 8. Handling Images 前言 本笔记是针对人工智能典型算法的课程中Machine Learning with Python Cookbook的学习笔记 学习的实战代码都放 ...

  5. Machine Learning with Python Cookbook 学习笔记 第6章

    Chapter 6. Handling Text 本笔记是针对人工智能典型算法的课程中Machine Learning with Python Cookbook的学习笔记 学习的实战代码都放在代码压缩 ...

  6. Python Cookbook 3rd Edition Documentation

    Python Cookbook 3rd Edition Documentation 文章目录 第一章:数据结构和算法 1.1 解压序列赋值给多个变量 问题 解决方案 讨论 1.2 解压可迭代对象赋值给 ...

  7. Machine Learning with Python Cookbook 学习笔记 第9章

    Chapter 9. Dimensionality Reduction Using Feature Extraction 前言 本笔记是针对人工智能典型算法的课程中Machine Learning w ...

  8. 《Python Cookbook 3rd》笔记(5.18):将文件描述符包装成文件对象

    将文件描述符包装成文件对象 问题 你有一个对应于操作系统上一个已打开的 I/O 通道 (比如文件.管道.套接字等)的整型文件描述符,你想将它包装成一个更高层的 Python 文件对象. 解法 一个文件 ...

  9. 《Python Cookbook 3rd》笔记(5.1):读写文本数据

    读写文本数据 问题 你需要读写各种不同编码的文本数据,比如 ASCII,UTF-8 或 UTF-16 编码等. 解法 使用带有 rt 模式的 open() 函数读取文本文件(t表示text文本模式,默 ...

最新文章

  1. python 归一化_只需 45 秒,Python 给故宫画一组手绘图!
  2. quartz 两个java_spring boot整合quartz实现多个定时任务的方法
  3. 几个比较实用的CSS
  4. 百度单测生成技术如何召回线上服务的异常问题?
  5. 音视频技术开发周刊 | 132(FFmpeg决策委员会委员 刘歧)
  6. sap获取系统时间_获取系统当前时间
  7. mysql datetime timestamp 索引_MYSQL中时间类型底层存储,DATETIME ,TIMESTAMP,INT 如何选择?...
  8. SQLite | Where 子句
  9. python 代码_如何让Python代码加速运行?
  10. STemwin替换为MDK下的emwin
  11. 网易云api及 asrsea 加密参数文档
  12. 自动化查询及增加配置参数功能
  13. java 数独 gui,GitHub - fagen/sudoku: 数独终局生成器和GUI
  14. 上交所实时行情文件汇总
  15. Day9 化学方程式配平
  16. 公司股权外部转让流程
  17. 【愚公系列】2023年06月 网络安全(交通银行杯)-木册木兰
  18. 哪家宽带网速是最好最快的?
  19. 对于给定的正整数N,需要计算 S=1!+2!+3!+...+N!
  20. linux中常见的校验用正则表达式

热门文章

  1. java递增_java-8 – 如何按组递增
  2. 正确断开计算机和网络的方法是,网络管理与维护-题库
  3. 卸载idea_IDEA 不为人知的 5 个骚技巧!真香!
  4. CSS一个元素同时使用多个类选择器(class selector)
  5. iis运行原理 Asp.Net详解IIS内部运行原理
  6. 【转】VSTS中版本控制系统Git与TFVC的区别
  7. 一步步编写操作系统 55 CPL和DPL入门2
  8. 投标报价得分计算程序_什么是投标报价?怎么计算呢?
  9. Coding Pages 申请 SSL 证书错误:urn:acme:error:unauthorized: Invalid response from http://xxxxx/
  10. mysql 事务实例_mysql实现事务的提交和回滚实例