写点什么

Python 文件和操作系统基础

作者:timerring
  • 2023-05-04
    山东
  • 本文字数:2811 字

    阅读完需:约 9 分钟

文章和代码等已经归档至【Github 仓库:https://github.com/timerring/dive-into-AI 】或者【AIShareLab】回复 python 数据分析 也可获取。

文件和操作系统

代码示例大多使用诸如 pandas.read_csv 之类的高级工具将磁盘上的数据文件读入 Python 数据结构。但我们还是需要了解一些有关 Python 文件处理方面的基础知识。


为了打开一个文件以便读写,可以使用内置的 open 函数以及一个相对或绝对的文件路径:


In [207]: path = 'examples/segismundo.txt'
In [208]: f = open(path)
复制代码


默认情况下,文件是以只读模式('r')打开的。然后,我们就可以像处理列表那样来处理这个文件句柄 f 了,比如对行进行迭代:


for line in f:    pass
复制代码


从文件中取出的行都带有完整的行结束符(EOL),因此你常常会看到下面这样的代码(得到一组没有 EOL 的行):


In [209]: lines = [x.rstrip() for x in open(path)]
In [210]: linesOut[210]: ['Sueña el rico en su riqueza,', 'que más cuidados le ofrece;', '', 'sueña el pobre que padece', 'su miseria y su pobreza;', '', 'sueña el que a medrar empieza,', 'sueña el que afana y pretende,', 'sueña el que agravia y ofende,', '', 'y en el mundo, en conclusión,', 'todos sueñan lo que son,', 'aunque ninguno lo entiende.', '']
复制代码


如果使用 open 创建文件对象,一定要用 close 关闭它。关闭文件可以返回操作系统资源:


In [211]: f.close()
复制代码


with 语句可以更容易地清理打开的文件


In [212]: with open(path) as f:   .....:     lines = [x.rstrip() for x in f]
复制代码


这样可以在退出代码块时,自动关闭文件。


如果输入 f =open(path,'w'),就会有一个新文件被创建在 examples/segismundo.txt,并覆盖掉该位置原来的任何数据。另外有一个 x 文件模式,它可以创建可写的文件,但是如果文件路径存在,就无法创建。表 3-3 列出了所有的读/写模式。



对于可读文件,一些常用的方法是 read、seek 和 tell。read 会从文件返回字符。字符的内容是由文件的编码决定的(如 UTF-8),如果是二进制模式打开的就是原始字节:


In [213]: f = open(path)
In [214]: f.read(10)Out[214]: 'Sueña el r'
In [215]: f2 = open(path, 'rb') # Binary mode
In [216]: f2.read(10)Out[216]: b'Sue\xc3\xb1a el '
复制代码


read 模式会将文件句柄的位置提前,提前的数量是读取的字节数。tell 可以给出当前的位置:


In [217]: f.tell()Out[217]: 11
In [218]: f2.tell()Out[218]: 10
复制代码


尽管我们从文件读取了 10 个字符,位置却是 11,这是因为用默认的编码用了这么多字节才解码了这 10 个字符。你可以用 sys 模块检查默认的编码:


In [219]: import sys
In [220]: sys.getdefaultencoding()Out[220]: 'utf-8'
复制代码


seek 将文件位置更改为文件中的指定字节:


In [221]: f.seek(3)Out[221]: 3
In [222]: f.read(1)Out[222]: 'ñ'
复制代码


最后,关闭文件:


In [223]: f.close()
In [224]: f2.close()
复制代码


向文件写入,可以使用文件的 write 或 writelines 方法。例如,我们可以创建一个无空行版的 prof_mod.py:


In [225]: with open('tmp.txt', 'w') as handle:   .....:     handle.writelines(x for x in open(path) if len(x) > 1)
In [226]: with open('tmp.txt') as f: .....: lines = f.readlines()
In [227]: linesOut[227]: ['Sueña el rico en su riqueza,\n', 'que más cuidados le ofrece;\n', 'sueña el pobre que padece\n', 'su miseria y su pobreza;\n', 'sueña el que a medrar empieza,\n', 'sueña el que afana y pretende,\n', 'sueña el que agravia y ofende,\n', 'y en el mundo, en conclusión,\n', 'todos sueñan lo que son,\n', 'aunque ninguno lo entiende.\n']
复制代码


表 3-4 列出了一些最常用的文件方法。


文件的字节和 Unicode

Python 文件的默认操作是“文本模式”,也就是说,你需要处理 Python 的字符串(即 Unicode)。它与“二进制模式”相对,文件模式加一个 b。我们来看上一节的文件(UTF-8 编码、包含非 ASCII 字符):


In [230]: with open(path) as f:   .....:     chars = f.read(10)
In [231]: charsOut[231]: 'Sueña el r'
复制代码


UTF-8 是长度可变的 Unicode 编码,所以当我从文件请求一定数量的字符时,Python 会从文件读取足够多(可能少至 10 或多至 40 字节)的字节进行解码。如果以“rb”模式打开文件,则读取确切的请求字节数:


In [232]: with open(path, 'rb') as f:   .....:     data = f.read(10)
In [233]: dataOut[233]: b'Sue\xc3\xb1a el '
复制代码


取决于文本的编码,你可以将字节解码为 str 对象,但只有当每个编码的 Unicode 字符都完全成形时才能这么做:


In [234]: data.decode('utf8')Out[234]: 'Sueña el '
In [235]: data[:4].decode('utf8')---------------------------------------------------------------------------UnicodeDecodeError Traceback (most recent call last)<ipython-input-235-300e0af10bb7> in <module>()----> 1 data[:4].decode('utf8')UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc3 in position 3: unexpected end of data
复制代码


文本模式结合了 open 的编码选项,提供了一种更方便的方法将 Unicode 转换为另一种编码:


In [236]: sink_path = 'sink.txt'
In [237]: with open(path) as source: .....: with open(sink_path, 'xt', encoding='iso-8859-1') as sink: .....: sink.write(source.read())
In [238]: with open(sink_path, encoding='iso-8859-1') as f: .....: print(f.read(10))Sueña el r
复制代码


注意,不要在二进制模式中使用 seek。如果文件位置位于定义 Unicode 字符的字节的中间位置,读取后面会产生错误:


In [240]: f = open(path)
In [241]: f.read(5)Out[241]: 'Sueña'
In [242]: f.seek(4)Out[242]: 4
In [243]: f.read(1)---------------------------------------------------------------------------UnicodeDecodeError Traceback (most recent call last)<ipython-input-243-7841103e33f5> in <module>()----> 1 f.read(1)/miniconda/envs/book-env/lib/python3.6/codecs.py in decode(self, input, final) 319 # decode input (taking the buffer into account) 320 data = self.buffer + input--> 321 (result, consumed) = self._buffer_decode(data, self.errors, final) 322 # keep undecoded input until the next call 323 self.buffer = data[consumed:]UnicodeDecodeError: 'utf-8' codec can't decode byte 0xb1 in position 0: invalid start byte
In [244]: f.close()
复制代码


如果你经常要对非 ASCII 字符文本进行数据分析,通晓 Python 的 Unicode 功能是非常重要的。更多内容,参阅 Python 官方文档。

发布于: 40 分钟前阅读数: 5
用户头像

timerring

关注

公众号【AIShareLab】 2022-07-14 加入

他日若遂凌云志

评论

发布
暂无评论
Python文件和操作系统基础_Python_timerring_InfoQ写作社区