'''
一、文件操作(读写追加,其他方法)
f = open(文件,mode="模式", encoding="编码")
模式:
r:只读
w:只写
a:追加写
+:扩展
b:字节(非文本文件)
读取文件最好的方案
with open() as f:
for line in f:
line = line.strip()
修改文件:
1、创建一个文件副本。
2、把源文件中的内容读取到内存。
3、然后再内存中进行修改。
4、修改之后保存在文件副本中。
5、把源文件删除。
6、把文件副本更改名称为源文件的名称。
1.1.初识文件操作
使用python来读写文件是非常简单的操作。我们使用open()函数来打开一个文件,获取到文件句柄。
然后通过文件句柄就可以进行各种各样的操作了。根据打开方式的不同能够执行的操作也会有相应的差异。
打开文件的方式:r, w, a, r+, w+, a+, rb, wb, ab, r+b, w+b, a+b默认使用的是r(只读)模式
1.2.只读操作(r, rb)
需要注意encoding表示编码,根据文件的实际保存编码进行获取数据,对于我们而言,更多的是utf-8.
'''
'''1.写模式(w, wb)
写的时候注意,如果没有文件,则会创建文件,如果文件存在,则将原件中原来的内容删除,再写入新内容'''
f = open("a1.txt", "w", encoding="utf-8")
f.write("苹果
")
f.write("桃子
")
f.write("香蕉
")
f.close()
'''w只读write模式,写会报错'''
f = open("a1.txt", "w", encoding="utf-8")
f.write("苹果
")
f.write("桃子
")
f.write("香蕉
")
content = f.read() # UnsupportedOperation: not readable
f.close()
---------------------------------------------------------------------------
UnsupportedOperation Traceback (most recent call last)
<ipython-input-129-01a25d1ab733> in <module>()
4 f.write("桃子
")
5 f.write("香蕉
")
----> 6 content = f.read() # UnsupportedOperation: not readable
7 f.close()
UnsupportedOperation: not readable
'''
wb模式下,不指定打开文件的编码,但是在写文件的时候必须将字符串转换成utf-8的bytes数据。
'''
f = open("c1.txt", mode="wb")
print("橙汁".encode("utf-8")) # b'xe6xa9x99xe6xb1x81'
f.write("橙汁".encode("utf-8"))
f.flush()
f.close()
b'xe6xa9x99xe6xb1x81'
'''
2.r只读read模式,read()将文件中的内容全部读取出来,弊端:占内存,如果文件过大。容易导致内存崩溃。
'''
f = open("a1.txt", mode="r", encoding="utf-8")
content = f.read()
print(content)
f.close()
苹果
桃子
香蕉
'''r只读read模式,写会报错'''
f = open("a1.txt", mode="r", encoding="utf-8")
content = f.read()
print(content)
f.write("aaa") # UnsupportedOperation: not writable
f.close()
---------------------------------------------------------------------------
UnsupportedOperation Traceback (most recent call last)
<ipython-input-132-1bb711d148ec> in <module>()
3 content = f.read()
4 print(content)
----> 5 f.write("aaa") # UnsupportedOperation: not writable
6 f.close()
UnsupportedOperation: not writable
'''
rb读取出来的数据是bytes类型,在rb模式下,不能选择encoding字符集。
rb的作用:在读取非文本文件的时候,比如读取MP3、图像、视频、直播等信息的时候就需要用到rb。因为这种数据是没办法直接显示出来的。
在后面我们文件上传下载的时候还会用到。
'''
f = open("a1.txt", "rb")
content = f.read() # read一次把文件内容读取完,type类型
print(content) # utf-8编码下,一个汉字是3个字节,一个字节是8位,gbk编码下,一个汉字是2个字节
f.close()
b'xe8x8bxb9xe6x9ex9c
xe6xa1x83xe5xadx90
xe9xa6x99xe8x95x89
'
'''
read(n)读取n个字符。需要注意的是,如果每次读取,那么会在当前位置继续去读取而不是从头读。
如果使用的是rb模式,则读取出来的是n个字节。
'''
f = open("a1.txt", mode="r", encoding="utf-8")
content = f.read(4) # 4个字符
print(content)
f.close()
苹果
桃
'''
readline()一次读取一行数据,注意:readline()结尾,注意每次读取出来的数据都会有一个
,需要我们使用strip()方法来去掉
或者空格。
'''
f = open("a1.txt", mode="r", encoding="utf-8")
content = f.readline() # 读取一行
print(content)
content2 = f.readline() # 读取一行
print(content2)
content3 = f.readline() # 读取一行
print(content3)
f.close()
苹果
桃子
香蕉
'''
readlines()将每一行形成一个元素,放到一个列表中。将所有的内容都读取出来,容易出现内存崩溃的问题,不推荐使用。
'''
f = open("a1.txt", mode="r", encoding="utf-8")
lst = f.readlines() # 一次把文件读取完,每行为一个元素,放入列表中
print(lst) # ['苹果
', '桃子
', '香蕉']
for line in lst:
print(line.strip())
f.close()
['苹果
', '桃子
', '香蕉
']
苹果
桃子
香蕉
'''
for循环读取,这种方式是最好的,每次读取一行内容,不会产生内存溢出的问题。
'''
f = open("a1.txt", mode="r", encoding="utf-8")
for line in f: # 节省内存,一行一行读取
print(line.strip())
f.close()
苹果
桃子
香蕉
'''
3.追加(a, ab)
只要是a、ab、a+都是在文件的末尾写入,不论光标在任何位置。
在追加模式下,我们写入的内容会追加在文件的结尾。
'''
f = open("a1.txt", mode="a", encoding="utf-8")
f.write("南果梨")
f.flush()
f.close()
'''ab和wb追加写和只写模式的时候,记得编码后再写入'''
f = open("a1.txt", mode="ab")
f.write("天山雪莲".encode("utf-8"))
f.flush()
f.close()
'''
4.读写模式(r+, r+b)
对于读写模式,必须是先读,因为默认光标是在开头的。当读完了之后再进行写入,我以后使用频率最高的模式是r+
正确操作:
'''
f = open("a1.txt", mode="r+", encoding="utf-8")
content = f.read()
print(content)
f.close()
苹果
桃子
香蕉
南果梨天山雪莲
'''r+先读取,光标移动到最后,再写入,写入的内容是在最后,然后把光标移动到开始的位置,重新读取'''
f = open("a1.txt", mode="r+", encoding="utf-8")
f.read()
f.write("读完了写入
")
f.seek(0)
content = f.read()
print(content)
f.close()
苹果
桃子
香蕉
南果梨天山雪莲读完了写入
'''r+必须是先读,后写,容易出现字符编码问题,会遇到下面的报错'''
f = open("a1.txt", mode="r+", encoding="utf-8")
f.write("先写。")
now_seek = f.tell()
print(now_seek)
f.seek(0)
content = f.read() # UnicodeDecodeError: 'utf-8' codec can't decode byte 0xa1 in position 9: invalid start byte
print(content)
f.close()
---------------------------------------------------------------------------
UnicodeDecodeError Traceback (most recent call last)
<ipython-input-141-3dd82e9e1e9a> in <module>()
5 print(now_seek)
6 f.seek(0)
----> 7 content = f.read() # UnicodeDecodeError: 'utf-8' codec can't decode byte 0xa1 in position 9: invalid start byte
8 print(content)
9 f.close()
~Anaconda3libcodecs.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 0xa1 in position 9: invalid start byte
'''1.写模式(w, wb)
写的时候注意,如果没有文件,则会创建文件,如果文件存在,则将原件中原来的内容删除,再写入新内容'''
f = open("a1.txt", "w", encoding="utf-8")
f.write("苹果
")
f.write("桃子
")
f.write("香蕉
")
f.close()
'''
错误操作:
结果:将开头的内容改成了“石榴”,然后读取的内容是后面的内容。
所以记住:r+模式下,必须是先读取,然后再写入
'''
f = open("a1.txt", mode="r+", encoding="utf-8")
f.write("石榴")
f.seek(0)
content = f.read()
print(content)
f.flush()
f.close()
石榴
桃子
香蕉
'''
seek(n)光标移动到n的位置,注意,移动的单位是byte。所以如果是UTF-8的中文部分要是3的倍数。
通常我们使用seek都是移动到开头或者结尾。
移动到开头:seek(0)
移动到结尾:seek(0, 2) seek的第二个参数表示的是从哪个位置进行偏移,默认是0,表示开头,1表示当前位置,2表示结尾。
'''
f = open("a1.txt", mode="r+", encoding="utf-8")
f.seek(0) # 光标移动到开头,此行可有可无
content = f.read() # 读取内容,此时光标移动到结尾
print(f"content: {content}
")
f.seek(0) # 再次将光标移动到开头
content2 = f.read()
print(f"content2: {content2}
")
f.seek(0, 2) # 将光标移动到结尾
content3 = f.read() # 读取内容,什么都没有
print(f"content3: {content3}
")
f.seek(0) # 移动到开头
f.write("苹果") # 写入信息,此时光标在6 中文2*3 = 6
f.flush()
f.close()
content: 石榴
桃子
香蕉
content2: 石榴
桃子
香蕉
content3:
'''
tell()可以帮我们获取到当前光标在什么位置
'''
f = open("a1.txt", mode="r+", encoding="utf-8")
f.seek(0) # 光标移动到开头
content = f.read() # 读取内容,此时光标移动到结尾
print(content)
f.seek(0) # 再次将光标移动到开头
f.seek(0, 2) # 将光标移动到结尾
content2 = f.read() # 读取内容,什么都没有
print(content2)
f.seek(0) # 移动到开头
f.write("榴莲") # 写入信息,此时光标在6 中文3*2 = 6
print(f.tell()) # 光标的位置6
f.flush()
f.close()
苹果
桃子
香蕉
6
'''
truncate()截断文件
'''
f = open("d1.txt", mode="w", encoding="utf-8")
f.write("苹果") # 写入两个字符
f.seek(3) # 光标移动到3,也就是两个字中间
f.truncate() # 删除光标后面的所有内容
f.close()
'''
总结:
f.read(n) 如果是r模式打开,表示读取n个字符
f.read(n) 如果是rb模式打开,表示读取n个字节
f.seek(n) 表示n个字节,1中文由3个字节组成
'''
'''a+模式,不管光标移动到哪个位置,都是在最后写入内容'''
f = open("a1.txt", "a+", encoding="utf-8")
f.seek(0)
f.write("开始位置
")
f.seek(0)
content = f.read()
print(content)
f.close()
榴莲
桃子
香蕉
开始位置
'''
修改文件以及另一种打开文件的方式(重点)
文件修改:只能将文件中的内容读取到内存中,将信息修改完毕,然后将源文件删除,将新文件的名字改成老文件的名字。
'''
import os
with open("b1.txt", mode="r", encoding="utf-8") as f1,
open("b1.txt_temp", mode="w", encoding="utf-8") as f2:
for line in f1:
new_line = line.replace("砀山梨", "橙汁")
f2.write(new_line)
os.remove("b1.txt") # 删除源文件
os.rename("b1.txt_temp", "b1.txt") # 重命名新文件
import requests
url = "https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2241880857,977619289&fm=26&gp=0.jpg"
content = requests.get(url).content
with open("flower.jpg", "wb") as f: # 将图片写入文件
f.write(content)