文件读写补充(大文件的读取+文件的写入+二进制文件的读写+super() 2020-12-4

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方法中去写就可以了。
截图
在这里插入图片描述

4. 作业

4.1 写博客梳理知识点

4.2 课堂代买最少敲三遍

猜你喜欢

转载自blog.csdn.net/m0_46738467/article/details/110670474