打印不合法的文件名

问题

你的程序获取了一个目录中的文件名列表,但是当它试着去打印文件名的时候程序崩溃,出现了 UnicodeEncodeError 异常和一条奇怪的消息—— surrogates not allowed 。

解法

当打印未知的文件名时,使用下面的方法可以避免这样的错误:

def bad_filename(filename):return repr(filename)[1:-1]try:print(filename)
except UnicodeEncodeError:print(bad_filename(filename))

讨论

这一小节讨论的是在编写必须处理文件系统的程序时一个不太常见但又很棘手的问题。默认情况下,Python假定所有文件名都已经根据sys.getfilesystemencoding()的值编码过了。但是,有一些文件系统并没有强制要求这样做,因此允许创建文件名没有正确编码的文件。这种情况不太常见,但是总会有些用户冒险这样做或者是无意之中这样做了(可能是在一个有缺陷的代码中给open()函数传递了一个不合规范的文件名)。

当执行类似os.listdir()这样的函数时,这些不合规范的文件名就会让Python陷入困境。一方面,它不能仅仅只是丢弃这些不合格的名字。而另一方面,它又不能将这些文件名转换为正确的文本字符串。Python对这个问题的解决方案是从文件名中获取未解码的字节值比如\xhh并将它映射成Unicode字符\udchh表示的所谓的“代理编码”。下面一个例子演示了当一个不合格目录列表中含有一个文件名为 bäd.txt(使用Latin-1而不是UTF-8编码)时的样子:

>>> import os
>>> files = os.listdir('.')
>>> files
['spam.py', 'b\udce4d.txt', 'foo.txt']
>>>

如果你有代码需要操作文件名或者将文件名传递给 open() 这样的函数,一切都能正常工作。只有当你想要输出文件名时才会碰到些麻烦 (比如打印输出到屏幕或日志文件等)。特别的,当你想打印上面的文件名列表时,你的程序就会崩溃:

>>> for name in files:
...     print(name)
...
spam.py
Traceback (most recent call last):File "<stdin>", line 2, in <module>
UnicodeEncodeError: 'utf-8' codec can't encode character '\udce4' in
position 1: surrogates not allowed
>>>

程序崩溃的原因就是字符 nudce4 是一个非法的 Unicode 字符。它其实是一个被称为代理字符对的双字符组合的后半部分。由于缺少了前半部分,因此它是个非法的Unicode。所以,唯一能成功输出的方法就是当遇到不合法文件名时采取相应的补救措施。比如可以将上述代码修改如下:

>>> for name in files:
... try:
...     print(name)
... except UnicodeEncodeError:
...     print(bad_filename(name))
...
spam.py
b\udce4d.txt
foo.txt
>>>

在 bad_filename() 函数中怎样处置取决于你自己。另外一个选择就是通过某种方式重新编码,示例如下:

def bad_filename(filename):temp = filename.encode(sys.getfilesystemencoding(), errors='surrogateescape')return temp.decode('latin-1')

surrogateescape:这种是 Python 在绝大部分面向 OS 的 API 中所使用的错误处理器,它能以一种优雅的方式处理由操作系统提供的数据的编码问题。在解码出错时会将出错字节存储到一个很少被使用到的 Unicode 编码范围内。在编码时将那些隐藏值又还原回原先解码失败的字节序列。它不仅对于 OS API 非常有用,也能很容易的处理其他情况下的编码错误。

使用这个版本产生的输出如下:

>>> for name in files:
...     try:
...         print(name)
...     except UnicodeEncodeError:
...         print(bad_filename(name))
...
spam.py
bäd.txt
foo.txt
>>>

这一小节主题可能会被大部分读者所忽略。但是如果你在编写依赖文件名和文件系统的关键任务程序时,就必须得考虑到这个。否则你可能会在某个周末被叫到办公室去调试一些令人费解的错误。

《Python Cookbook 3rd》笔记(5.15):打印不合法的文件名相关推荐

  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 学习笔记 第9章

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

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

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

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

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

  7. Python Cookbook 3rd Edition Documentation

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

  8. 《Python cookbook》笔记一

    <Python cookbook> 第一章 数据结构和算法 - *号解压多个变量 - 如果一个可迭代对象的元素个数超过变量个数时,会抛出一个 ValueError .那么 怎样才能从这个可 ...

  9. 《Python Cookbook 3rd》笔记(5.3):使用其他分隔符或行终止符打印

    使用其他分隔符或行终止符打印 问题 你想使用 print() 函数输出数据,但是想改变默认的分隔符或者行尾符. 解法 可以使用在 print() 函数中使用 sep 和 end 关键字参数,以你想要的 ...

最新文章

  1. Deep Learning – Review by LeCun, Bengio, and Hinton
  2. I2C总线以及GPIO模拟I2C
  3. python如何绘制两点间连线_如何利用Python的pyecharts绘制3d柱形图?
  4. Cannot maintain customer-spec. event handler registration in SAP system
  5. HDU2067 小兔的棋盘
  6. MVC下实现LayUI分页的Demo
  7. 周末直播丨细致入微 - OEM Grid Control 配置部署与使用
  8. 1078. Hashing (25)-PAT甲级真题
  9. CCS7.3 安装使用教程
  10. Matlab求平均值函数mean
  11. 第一章 计算机网络概述(计算机网络韩立刚)
  12. python把英语句子成分字母_英语句子成分分析报告(最完整版)
  13. Week15 - 程序设计思维与实践 - 字符串算法
  14. 怎么把电脑上的文件备份到百度网盘?
  15. 005. C++智能指针
  16. linux下要熟练掌握的常用快捷键和命令
  17. 自媒体多账号发布工具大全,快来看看
  18. 【DIY】制作一个刷卡进门装置
  19. Oracle -PL/SQL Developer错误解决方案(ORA-02291)
  20. 程序猿没有副业,太难了(个人经历不喜无视)

热门文章

  1. socket 编程入门教程(一)TCP server 端:4、构造函数涉及的概念
  2. python traceback 丢失_基于python traceback实现异常的获取与处理
  3. 安徽大学计算机考研学硕2019初试单科线,安徽大学2019年考研复试分数线已公布...
  4. uln2003驱动蜂鸣器_让蜂鸣器发声
  5. 【转】C++中如何区分构造函数与重载operator()得到的仿函数?
  6. 【转】DevOps到底是什么意思?
  7. bat 脚本清空窗口内容_tomcat9.0启动脚本startup.bat的分析
  8. 【蓝桥官网试题 - 算法提高】change(思维)
  9. 【CodeForces - 1027C】Minimum Value Rectangle (数学,公式化简,思维,卡常卡memset)
  10. C++中两个常用的控制语句格式的函数(width和precision函数)