文章目录
第十七章 文件读写补充(大文件的读取+文件的写入+二进制文件的读写+super()
1. open()函数打开一个文件
用open()函数打开一个文件,可以将文件分为两种类型:
- 纯文本文件: 用utf-8编写的文本文件
- 二进制文件: 图片,音频,视频
文本打开后,英文纯文本可以直接读取,但中文纯文本需要使用encoding=‘utf-8’
file_name='Demo02.txt'
try:
with open(file_name,encoding='utf-8') as file_obj:
content = file_obj.read()
print(content)
except FileNotFoundError:
print(f'文件{file_name不存在}')
结果
Hello World!!!
白日依山尽
黄河入海流
欲穷千里目
更上一层楼
open()函数默认将文件一纯文本的模式打开。
read()会把文件内所有的内容全部读出来。如果文件较大,会导致内存空间不够。所以一般不直接使用read()函数。
1.1 大文件的读取方法
read()函数内部可以传入数字参数,代表每次打印的字符数。默认里面的参数是-1,比如我在这个例子中可以传入6作为参数,因为每行五个字加一个换行符,刚好是6个字符。但是最后一行不需要换行,有五个字符,但是还是传入6,并不报错。当字符数少于传入的参数时,所有的字符都被打印出来。
file_name='Demo02.txt'
try:
with open(file_name,encoding='utf-8') as file_obj:
content = file_obj.read(6)
print(content)
except FileNotFoundError:
print(f'文件{file_name不存在}')
结果
白日依山尽
如果我再加一行打印代码呢?
file_name='Demo02.txt'
try:
with open(file_name,encoding='utf-8') as file_obj:
content = file_obj.read(6)
content = file_obj.read(6)
print(content)
except FileNotFoundError:
print(f'文件{file_name不存在}')
结果、
黄河入海流
我们发现把前面的一句覆盖了,并不是打印出两句。这样我们就可以写一个循环来控制打印,把结果都打印出来,而且不是用read()函数一次都读出来,而是循序渐进的读出来。
file_name='Demo02.txt'
try:
with open(file_name,encoding='utf-8') as file_obj:
chunk = 100
while True:
content = file_obj.read(chunk)
if not content:
break
print(content)
except FileNotFoundError:
print(f'文件{file_name不存在}')
结果
白日依山尽
黄河入海流
欲穷千里目
更上一层楼
这是为了避免内存益处而进行一块一块的读取的方法。
1.2 文件的写入
open()函数默认的时打开只读文件,是不能写入内容的。如果要写入,打开的时候,要传入参数’w’,写入,如果文件里已经有内容,则内容被新写的内容覆盖,如果没有内容则写入内容。
file_name='Demo02.txt'
with open(file_name,'w',encoding='utf-8') as file_obj:
r=file_obj.write('今天是最后一节课啦啦啦')
print(r)
file_obj.close() # 关闭已经打开的文件
with open(file_name,'r',encoding='utf-8') as file_obj:
content = file_obj.read(100)
print(content)
结果
11
今天是最后一节课啦啦啦
我们看到文本Demo02.txt里的内容已经被新内容所覆盖。注意,write()函数内传入的内容只能是字符串,不能是数字或者其他。而且这个函数是有返回值的,返回的是所写入字符的个数。
如果不想之前的内容被覆盖,则打开的时候需要传入参数’a’,意思是追加。
file_name='Demo02.txt'
with open(file_name,'a',encoding='utf-8') as file_obj:
file_obj.write('这是追加的内容')
file_obj.close() # 关闭已经打开的文件
with open(file_name,'r',encoding='utf-8') as file_obj:
content = file_obj.read(100)
print(content)
结果
今天是最后一节课这是追加的内容
另外还有一个参数x,当使用open()函数打开时传入此参数,如果被打开的文件存在则报错,不存在则创建。
file_name='Demo04.txt'
with open(file_name,'a',encoding='utf-8') as file_obj:
file_obj.write('这是新键Demo04文件里写入的内容。')
file_obj.close() # 关闭已经打开的文件
with open(file_name,'r',encoding='utf-8') as file_obj:
content = file_obj.read(100)
print(content)
结果
2. 二进制文件的读写
下面我们通过做一个项目来了解二进制文件的读写,二进制文件时相对于纯文本文件来说的,是指图片,音频,视频等类文件。
例题:读取一个音乐文件“Break the dividing wal.mp3”,然后把它写入一个文件,并命名为“New_break the dividing wall.mp3”。
代码:
file_name= r'C:\Users\MI\OneDrive\桌面\Break the dividing wall.MP3' # 我事先在桌面放了一个音乐文件
with open(file_name,'rb') as file_obj: # 'rb'代表以二进制文件打开,没有传入这个参数默认的参数是't'这个参数可以不写,即纯文本的意思
#new_name = 'New_break dividing wall.mp3' 如果这样建,后面open()函数直接打开,就会在这个程序模块同一个文件夹里生成文件,不方便查找。所我把老师的代码改了。如下:
with open(r'C:\Users\MI\OneDrive\桌面\New_break dividing wall.mp3','wb') as new_obj:
chunk = 100 * 1024
while True:
content = file_obj.read(chunk)
if not content:
break
new_obj.write(content)
结果,这个结果不好展示,结果就是在我的桌面上出现了一个新的文件’New_break dividing wall.mp3’打开可以听,跟之前那个内容是一样的。实际上换成视频图片等,也是可以的。
3. super() (拓展)
这是和继承有关的知识点,如果子类也需要定义init方法,那么和父类的init方法会起冲突,为解决这个问题,Python专门定义了一个super()。关于它的用法,我们用一个实例来展示。
例子:
class Person:
def __init__(self):
self.name='张三'
self.age=18
def run(self):
print(f'{self.name}在跑步。')
def eat(self):
print(f'{self.name}在吃饭。')
class Students(Person):
pass
class Teachers(Person):
pass
s=Students()
s.run()
s.eat()
结果
张三在跑步。
张三在吃饭。
现在我想在子类中也定义一个init方法,当然是可以的:
class Person:
def __init__(self):
self.name='张三'
self.age=18
def run(self):
print(f'{self.name}在跑步。')
def eat(self):
print(f'{self.name}在吃饭。')
class Students(Person):
def __init__(self):
print('我是Students中的init方法')
class Teachers(Person):
pass
s=Students()
我们发现,在创建实例的时候是没问题的:
我是Students中的init方法
但是在调用方法的时候就报错了。
class Person:
def __init__(self):
self.name='张三'
self.age=18
def run(self):
print(f'{self.name}在跑步。')
def eat(self):
print(f'{self.name}在吃饭。')
class Students(Person):
def __init__(self):
print('我是Students中的init方法')
pass
class Teachers(Person):
pass
s=Students()
s.run()
结果
我是Students中的init方法
Traceback (most recent call last):
File "D:/work/基础/Day17/Demo01.py", line 59, in <module>
s.run()
File "D:/work/基础/Day17/Demo01.py", line 49, in run
print(f'{self.name}在跑步。')
AttributeError: 'Students' object has no attribute 'name'
说Students对象没有name这个属性,说明继承父类的时候失败了。子类的init方法和父类的init方法都是一开始就执行的,当然是后者覆盖了前者,而后者是没有定义name属性的。我们添加一行代码验证一下:
class Person:
def __init__(self):
self.name='张三'
self.age=18
print('我是Person中的init方法')
def run(self):
print(f'{self.name}在跑步。')
def eat(self):
print(f'{self.name}在吃饭。')
class Students(Person):
def __init__(self):
print('我是Students中的init方法')
pass
class Teachers(Person):
pass
s=Students()
结果
我是Students中的init方法
我们看只打印出了子类中的语句,再次印证了子类中的init方法覆盖掉了前面父类中的init方法。如果我们想要在子类定义自己的init方法,甚至我们可以定制属于子类属于自己的属性和方法,这里就需要用到super()类来解决问题了,话不多说,直接看代码:
class Person:
def __init__(self):
self.name='张三'
self.age=18
print('我是Person中的init方法')
def run(self):
print(f'{self.name}在跑步。')
def eat(self):
print(f'{self.name}在吃饭。')
class Students(Person):
def __init__(self):
print('我是Students中的init方法')
super().__init__() # 添加的代码
class Teachers(Person):
pass
s=Students()
s.run()
s.eat()
结果
我是Students中的init方法
我是Person中的init方法
张三在跑步。
张三在吃饭。
我们看到,当添加了
super().__init__()
这行代码以后,所有问题都解决了,子类成功继承了父类的属性,而且在父类的语句也被打印出来了,没有被后面子类的init方法覆盖。这行代码就相当于调用了父类的init方法。我们后面实例中调用run()和eat()这两个方法的时候,其中都有用到父类init方法里面定义的属性,所以后面必须要调用父类的init方法。现在,我们尝试在子类中定义自己的属性。
class Person:
def __init__(self,name,age):
self.name=name
self.age=age
print('我是Person中的init方法')
def run(self):
print(f'{self.name}在跑步。')
def eat(self):
print(f'{self.name}在吃饭。')
class Students(Person):
def __init__(self,name,age):
print('我是Students中的init方法')
super().__init__(name,age)
class Teachers(Person):
pass
s=Students('张三','18')
s.run()
s.eat()
结果
我是Students中的init方法
我是Person中的init方法
张三在跑步。
张三在吃饭。
截图
下面我们在学生的类里面在定义一个班级的属性:
class Person:
def __init__(self,name,age):
self.name=name
self.age=age
print('我是Person中的init方法')
def run(self):
print(f'{self.name}在跑步。')
def eat(self):
print(f'{self.name}在吃饭。')
class Students(Person):
def __init__(self,name,age,banji):
print('我是Students中的init方法')
super().__init__(name,age)
self.banji=banji
class Teachers(Person):
pass
s=Students('张三','18')
s.run()
s.eat()
print(s.banji)
结果
我是Students中的init方法
我是Person中的init方法
张三在跑步。
张三在吃饭。
Python基础班
我们看到全部运行了,没有问题了。总结一下:
如果子类继承父类,子类要定义一个init方法,要用super()调用父类的init方法,并且无论用不用,都要将父类里面的属性写入。子类独有的属性,在子类自己的init方法中去写就可以了。
截图