《手把手陪您学Python》32——文件的读取

在上一篇《手把手陪您学Python》31——文件的打开中,我们学习了文件打开的方法。今天我们继续学习文件的操作,会重点讲解几种文件读取的方法。

这里先多说一句。当我们以后学习了更高级的文件操作方法后,我们可能更多地会使用pandsa.read_csv这类读取文件的命令。但是,理解python处理文件的基础原理也是很重要的,也就是这篇文章要介绍的内容。

Python中有多种读取文件的方式,下面我们逐个介绍。

1、读取整个文件

在上一篇中我们看到,open()函数返回的只是一个迭代器,这时我们就需要read()方法来读取文件了,使用的方法就和我们之前使用的各种方法一样,就在对象后面加上“.”和方法名即可,此时我们就可以读取整个文件了。

In [1]: path = 'lesson/text/contents.txt'
        file_object = open(path, encoding = 'utf-8').read()
        print(file_object)
Out[1]: 《手把手陪您学Python》1——为什么要学Python?
        《手把手陪您学Python》2——Python的安装 
        《手把手陪您学Python》3——PyCharm的安装和配置 
        《手把手陪您学Python》4——Hello World!
        《手把手陪您学Python》5——Jupyter Notebook 
        《手把手陪您学Python》6——字符串的标识 
        《手把手陪您学Python》7——字符串的索引 
        《手把手陪您学Python》8——字符串的切片 
        《手把手陪您学Python》9——字符串的运算 
        《手把手陪您学Python》10——字符串的函数
         

打开的目标文件经过read()方法读取,就可以打印出我们期待的效果了。

虽然这样的输出结果,看上去与原始文件没有什么区别,但实际上还是有点不同的,那就是输出的结果中,末尾多了一个空行。

为什么会多出这个空行呢?因为在我们的目标文件中,在最后一行文字后面有个换行,read()到达文件末尾时会自动返回一个空字符串,换行加上这个空字符串显示出来时就是一个空行。要删除这个多出来的空行,一种办法是在制作目标文件时,避免出现最后的换行,另一种可以使用我们之前学到的string.rstrip(str)方法——用来截取掉字符串右边(结尾)的指定字符(str默认为空格)。

用这种方法再将程序修改一下,就可以得到和目标文件内容完全一致的结果了。

In [2]: path = 'lesson/text/contents.txt'
        file_object = open(path, encoding = 'utf-8').read()
        print(file_object.rstrip())
Out[2]: 《手把手陪您学Python》1——为什么要学Python?
        《手把手陪您学Python》2——Python的安装
        《手把手陪您学Python》3——PyCharm的安装和配置
        《手把手陪您学Python》4——Hello World!
        《手把手陪您学Python》5——Jupyter Notebook
        《手把手陪您学Python》6——字符串的标识
        《手把手陪您学Python》7——字符串的索引
        《手把手陪您学Python》8——字符串的切片
        《手把手陪您学Python》9——字符串的运算
        《手把手陪您学Python》10——字符串的函数

另外我们可以看一下,如果在读取中文字符而又没有使用encoding参数时会出现什么情况。

In [3]: path = 'lesson/text/contents.txt'
        file_object = open(path).read()
        print(file_object)
Out[3]: ---------------------------------------------------------------------------
        UnicodeDecodeError                        Traceback (most recent call last)
        <ipython-input-10-38447936f978> in <module>
              1 path = 'lesson/text/contents.txt'
        ----> 2 file_object = open(path).read()
              3 print(file_object)
              
        UnicodeDecodeError: 'gbk' codec can't decode byte 0xaa in position 14: illegal multibyte sequence

可以看到,当目标文件中包含中文字符,但是又没有使用encoding参数时,会出现gbk字符无法解码的错误。

由于大部分情况下我们的文件中多少都会有一些中文字符,包括中文的标点符号,所以建议在使用open()函数时,都习惯性地加上“encoding = 'utf-8'”的参数,确保不会因为编码问题而出错。

如果不清楚文件的编码,可以导入sys模块,使用getdefaultencoding()方法来检查文件的默认编码,但因为超出我们现在所学的太多,只是顺便提一句。

2、使用迭代器逐行读取文件

由于打开的文件返回的是一个迭代器,所以除了读取整个文件外,还可以利用for循环语句,逐行读取文件,就像遍历列表一样简单,输出的结果就是目标文件中的每一行。

In [4]: path = 'lesson/text/contents.txt'
        file_object = open(path, encoding = 'utf-8')
        for line in file_object:
            print(line)
Out[4]: 《手把手陪您学Python》1——为什么要学Python?

        《手把手陪您学Python》2——Python的安装
        
        《手把手陪您学Python》3——PyCharm的安装和配置
        
        《手把手陪您学Python》4——Hello World!
        
        《手把手陪您学Python》5——Jupyter Notebook
        
        《手把手陪您学Python》6——字符串的标识
        
        《手把手陪您学Python》7——字符串的索引
        
        《手把手陪您学Python》8——字符串的切片

        《手把手陪您学Python》9——字符串的运算
        
        《手把手陪您学Python》10——字符串的函数
        

可以看到,逐行读取并打印时,输出的结果空行就更多了,所以也需要rstrip()一下。

In [5]: path = 'lesson/text/contents.txt'
        file_object = open(path, encoding = 'utf-8')
        for line in file_object:
            print(line.rstrip())
Out[5]: 《手把手陪您学Python》1——为什么要学Python?
        《手把手陪您学Python》2——Python的安装
        《手把手陪您学Python》3——PyCharm的安装和配置
        《手把手陪您学Python》4——Hello World!
        《手把手陪您学Python》5——Jupyter Notebook
        《手把手陪您学Python》6——字符串的标识
        《手把手陪您学Python》7——字符串的索引
        《手把手陪您学Python》8——字符串的切片
        《手把手陪您学Python》9——字符串的运算
        《手把手陪您学Python》10——字符串的函数

如果用我们之前学习过的列表推导式,上面的程序可以更为简单。

In [6]: path = 'lesson/text/contents.txt'
        print([x for x in open(path, encoding = 'utf-8')])
Out[6]: ['《手把手陪您学Python》1——为什么要学Python?\n', '《手把手陪您学Python》2——Python的安装\n', '《手把手陪您学Python》3——PyCharm的安装和配置\n', '《手把手陪您学Python》4——Hello World!\n', '《手把手陪您学Python》5——Jupyter Notebook\n', '《手把手陪您学Python》6——字符串的标识\n', '《手把手陪您学Python》7——字符串的索引\n', '《手把手陪您学Python》8——字符串的切片\n', '《手把手陪您学Python》9——字符串的运算\n', '《手把手陪您学Python》10——字符串的函数\n']

列表推导式将目标文件中的每一行的内容以及换行符作为元素,组成了一个列表。所以每个元素后面都有一个换行的转义字符。之所以之前的实例结果中都没有包括转义字符,是因为使用了print()函数,如果之前的实例都不使用print()函数打印,也会出现换行的转义符,大家可以试一下。

如果要去掉这种转义符,也可以使用rstrip()方法。

In [7]: path = 'lesson/text/contents.txt'
        print([x.rstrip() for x in open(path, encoding = 'utf-8')])
Out[7]: ['《手把手陪您学Python》1——为什么要学Python?', '《手把手陪您学Python》2——Python的安装', '《手把手陪您学Python》3——PyCharm的安装和配置', '《手把手陪您学Python》4——Hello World!', '《手把手陪您学Python》5——Jupyter Notebook', '《手把手陪您学Python》6——字符串的标识', '《手把手陪您学Python》7——字符串的索引', '《手把手陪您学Python》8——字符串的切片', '《手把手陪您学Python》9——字符串的运算', '《手把手陪您学Python》10——字符串的函数']

在对open()后的文件进行逐行读取时要注意,生成的迭代器只能使用一次。因为逐行读取的过程中,指针会从文件的开头移动到末尾,而不会自动再回到开头。所以用for循环逐行读取的话,用且只能用一次。

3、使用readlines()方法逐行读取

除了用for循环实现逐行的读取外,还可以使用readlines()方法,此时返回的就是由各行内容组成的列表,比使用for循环生成列表的方式更为简单。

In [8]: path = 'lesson/text/contents.txt'
        file_object = open(path, encoding = 'utf-8').readlines()
        print(file_object)
Out[8]: ['《手把手陪您学Python》1——为什么要学Python?\n', '《手把手陪您学Python》2——Python的安装\n', '《手把手陪您学Python》3——PyCharm的安装和配置\n', '《手把手陪您学Python》4——Hello World!\n', '《手把手陪您学Python》5——Jupyter Notebook\n', '《手把手陪您学Python》6——字符串的标识\n', '《手把手陪您学Python》7——字符串的索引\n', '《手把手陪您学Python》8——字符串的切片\n', '《手把手陪您学Python》9——字符串的运算\n', '《手把手陪您学Python》10——字符串的函数\n']

使用readlines()方法时,也同样是通过指针的移动进行读取的,所以和上面的for循环一样,readlines()的方法也只能使用一次。

4、读取指定个字符

使用read()方法除了可以读取整个文件,当输入参数时,还可以读取从头开始的指定个数的字符,字符的个数就是参数。

In [9]: path = 'lesson/text/contents.txt'
        file_object = open(path, encoding = 'utf-8').read(100)   # 读取100个字符
        print(file_object)
Out[9]: 《手把手陪您学Python》1——为什么要学Python?
        《手把手陪您学Python》2——Python的安装
        《手把手陪您学Python》3——PyCharm的安装和配置
        《手把手陪您学Pytho

5、返回指针位置

刚才我们说了很多次指针的移动,文件的读取过程实际上就是通过指针或者叫做句柄的推进来实现的。

read()方法默认是从文件的第1个字符开始的(指针也在第一个字符的位置),结束时指针会自动移动到下一个字符的位置,并准备下一次的读取指令。

通过tell()方法,可以返回指针当前的位置。

In [10]: path = 'lesson/text/contents.txt'
         file_object = open(path, encoding = 'utf-8')
         print(file_object.read(8))
         file_object.tell()
Out[10]: 《手把手陪您学P
         22

在UTF-8格式中,每个中文字符和中文标点符号占用3字节的位置。所以在上面的例子中,当read读8个字符时,其中包括7个中文字符(含中文符号)占用21字节,和1个英文占用1字节,所以最后指针的位置在22字节处。

利用指针,我们就可以验证上面所说的for循环只能用一次的原理了。

In [11]: path = 'lesson/text/contents.txt'
         file_object = open(path, encoding = 'utf-8')
         for line in file_object:
             print(line.rstrip())
         file_object.tell()
Out[11]: 《手把手陪您学Python》1——为什么要学Python?
         《手把手陪您学Python》2——Python的安装
         《手把手陪您学Python》3——PyCharm的安装和配置
         《手把手陪您学Python》4——Hello World!
         《手把手陪您学Python》5——Jupyter Notebook
         《手把手陪您学Python》6——字符串的标识
         《手把手陪您学Python》7——字符串的索引
         《手把手陪您学Python》8——字符串的切片
         《手把手陪您学Python》9——字符串的运算
         《手把手陪您学Python》10——字符串的函数
         575

经过一次遍历后,指针如同上面所说的,移动到了文章的末尾,此时在575字节的位置,计算的方法和上面一样,所以就不能再使用for循环遍历,或者使用readlines()的方法了。

6、移动指针到指定位置

如果要自行控制指针的位置,可以使用seek()方法,将指针移动到指定位置,并配合read()方法读取文件的剩余部分或者指定个数的字符。

In [12]: path = 'lesson/text/contents.txt'
         file_object = open(path, encoding = 'utf-8')
         file = file_object.seek(22)
         file_object.tell()
         print(file_object.read())
Out[12]: ython》1——为什么要学Python?
         《手把手陪您学Python》2——Python的安装
         《手把手陪您学Python》3——PyCharm的安装和配置
         《手把手陪您学Python》4——Hello World!
         《手把手陪您学Python》5——Jupyter Notebook
         《手把手陪您学Python》6——字符串的标识
         《手把手陪您学Python》7——字符串的索引
         《手把手陪您学Python》8——字符串的切片
         《手把手陪您学Python》9——字符串的运算
         《手把手陪您学Python》10——字符串的函数

在上面的实例中,先使用seek()方法将指针移动到22字节的位置(和之前的实例位置一样),之后用tell()方法进行了验证,最后使用read()方法读取指针位置后的剩余内容。

使用seek()移动指针时要注意,涉及到中文字符时,是不能把中文字符的字节拆开的。比如,目标文件中的第一个字符是中文的“《”,占用3字节的位置,如果只是seek()1或者2是没有问题的,但如果要将指针移动到1字节或者2字节的位置以后再打印,就会报错了。

In [13]: path = 'lesson/text/contents.txt'
         file_object = open(path, encoding = 'utf-8')
         file = file_object.seek(2)
         print(file_object.read())
Out[13]: ---------------------------------------------------------------------------
         UnicodeDecodeError                        Traceback (most recent call last)
         <ipython-input-76-27e34aade1ea> in <module>
               2 file_object = open(path, encoding = 'utf-8')
               3 file = file_object.seek(2)
         ----> 4 print(file_object.read())

         ~\anaconda3\lib\codecs.py in decode(self, input, final)
             320         # decode input (taking the buffer into account)
             321         data = self.buffer + input
         --> 322         (result, consumed) = self._buffer_decode(data, self.errors, final)
             323         # keep undecoded input until the next call
             324         self.buffer = data[consumed:]

         UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8a in position 0: invalid start byte

报错的内容就是当指针在中文字符所占用连续字节的位置的中间时,是无法解码的。

同样,利用seek(),可以在for循环遍历文件后,通过将指针移动到初始位置,就可以进行再一次的遍历了。

In [14]: path = 'lesson/text/contents.txt'
         file_object = open(path, encoding = 'utf-8')
         for line in file_object:
             print(line.rstrip())
         file_object.seek(0)
         for line in file_object:
             print(line.rstrip())
Out[14]: 《手把手陪您学Python》1——为什么要学Python?
         《手把手陪您学Python》2——Python的安装
         《手把手陪您学Python》3——PyCharm的安装和配置
         《手把手陪您学Python》4——Hello World!
         《手把手陪您学Python》5——Jupyter Notebook
         《手把手陪您学Python》6——字符串的标识
         《手把手陪您学Python》7——字符串的索引
         《手把手陪您学Python》8——字符串的切片
         《手把手陪您学Python》9——字符串的运算
         《手把手陪您学Python》10——字符串的函数
         《手把手陪您学Python》1——为什么要学Python?
         《手把手陪您学Python》2——Python的安装
         《手把手陪您学Python》3——PyCharm的安装和配置
         《手把手陪您学Python》4——Hello World!
         《手把手陪您学Python》5——Jupyter Notebook
         《手把手陪您学Python》6——字符串的标识
         《手把手陪您学Python》7——字符串的索引
         《手把手陪您学Python》8——字符串的切片
         《手把手陪您学Python》9——字符串的运算
         《手把手陪您学Python》10——字符串的函数

以上就是Python读取文件的几种基础方法,希望大家能够好好理解,会有助于我们后面学习更高级的文件读取的操作的。

下一篇,我们将要介绍关闭文件以及写入文件的方法,敬请关注。

 

图片

 


感谢阅读本文!如有任何问题,欢迎留言,一起交流讨论^_^

要阅读《手把手陪您学Python》系列文章的其他篇目,请关注公众号点击菜单选择,或点击下方链接直达。

《手把手陪您学Python》1——为什么要学Python?

《手把手陪您学Python》2——Python的安装

《手把手陪您学Python》3——PyCharm的安装和配置

《手把手陪您学Python》4——Hello World!

《手把手陪您学Python》5——Jupyter Notebook

《手把手陪您学Python》6——字符串的标识

《手把手陪您学Python》7——字符串的索引

《手把手陪您学Python》8——字符串的切片

《手把手陪您学Python》9——字符串的运算

《手把手陪您学Python》10——字符串的函数

《手把手陪您学Python》11——字符串的格式化输出

《手把手陪您学Python》12——数字

《手把手陪您学Python》13——运算

《手把手陪您学Python》14——交互式输入

《手把手陪您学Python》15——判断语句if

《手把手陪您学Python》16——循环语句while

《手把手陪您学Python》17——循环的终止

《手把手陪您学Python》18——循环语句for

《手把手陪您学Python》19——第一阶段小结

《手把手陪您学Python》20——列表

《手把手陪您学Python》21——元组

《手把手陪您学Python》22——字典

《手把手陪您学Python》23——内置序列函数

《手把手陪您学Python》24——集合

《手把手陪您学Python》25——列表推导式

《手把手陪您学Python》26——自定义函数

《手把手陪您学Python》27——自定义函数的参数

《手把手陪您学Python》28——自定义函数的返回值

《手把手陪您学Python》29——匿名函数

《手把手陪您学Python》30——模块

《手把手陪您学Python》31——文件的打开

For Fans:关注“亦说Python”公众号,回复“手32”,即可免费下载本篇文章所用示例语句。

亦说Python——Python爱好者的学习分享园地
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值