文件操作
1 创建格式
open() 将会返回一个 file 对象,基本语法格式如下:
open(file, mode=‘r’, buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
参数:
filename:必需,文件路径(相对或者绝对路径)/要访问的文件名称的字符串值。
mode:决定了打开文件的模式:只读,写入,追加等。默认文件访问模式为只读®。
buffering: 设置缓冲
encoding: 设置编码格式
errors: 报错级别
newline: 区分换行符
closefd: 传入的file参数类型
t: 文本模式 (默认)。
r: 以只读方式打开。文件指针在文件的起始位置。默认模式。
r+: 打开,用于读写。文件指针在文件的起始位置。
x: 写模式,新建一个文件,如果该文件已存在则会报错。
w: 打开,只用于写入。如果该文件已存在则覆盖原文件。如果该文件不存在,创建新文件。
w+: 打开,用于读写。如果该文件已存在则覆盖原文件。如果该文件不存在,创建新文件。
a: 以追加方式打开。如果该文件已存在,文件指针在文件的结尾。在文件内容结尾写入内容,如果该文件不存在,创建新文件进行写入。
a+: 打开,用于读写。如果该文件已存在,文件指针在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。
rb: 以二进制格式打开,用于只读。文件指针在文件的起始位置。
# "b"表示处理二进制文件(如:FTP发送上传ISO镜像文件,linux可忽略,windows处理二进制文件时需标注)
rb+: 以二进制格式打开,用于读写。文件指针在文件的起始位置。
wb: 以二进制格式打开,只用于写入。如果该文件已存在则覆盖原文件。如果该文件不存在,创建新文件。
wb+: 以二进制格式打开,用于读写。如果该文件已存在则覆盖原文件。如果该文件不存在,创建新文件。
ab: 以二进制格式打开,用于追加。如果该文件已存在,文件指针在文件的结尾。在文件内容结尾写入内容,如果该文件不存在,创建新文件进行写入。
ab+: 以二进制格式打开,用于追加。如果该文件已存在,文件指针在文件的结尾。如果该文件不存在,创建新文件用于读写。
注意: 无论"r+", “w+”, "a+"写入内容只能是在文件结尾追加内容,无法插入写入
2 常用功能
** testfile内容:**
これ以上(いじょぅ)なにをうしなえば こころはゆるされるの
还要再失去什么 才能让心得到宽恕?
どれ程(ほど)の痛(いた)みならば もういちどきみにあえる
还要再怎样痛楚 才能与你再次相见
One more time 季節(きせつ)よ うつろわないで
One more time 不愿看到季节的变迁
One more time ふざけあった時間(じかん)よ
One more time 曾与你嬉闹的时光啊
くいちがうときはいつも 僕(ぼく)が先(さき)におれたね
每次争执的时候 都是我首先让步
わがままな性格(せいかく)が なおさら愛(いと)しくさせた
你那任性的性格 反令你更加可爱
One more chance 記憶(きおく)に足(あし)を取(と)られて
One more chance 回忆绊住我的脚步
2.1 读文件
# 不推荐使用此方法读取文件,原因是功能单一(只能读),无法对文件进行后续操作
data = open("testfile", encoding="utf-8").read()
print("打印data内容:\n%s" % data)
# "r" 读文件
# 将打开的文件赋一个变量,便于后期操作
# 执行读文件操作时,开始读文件的指针指向文件起始位置,读完后则停留在结尾位置;
# 此时再执行读文件操作时,由于指针指向文件结尾位置,所读内容为空;
# 需要重设指针重新指向文件起始位置,才能重新读取文件内容
f = open("testfile", "r", encoding="utf-8")
# read()从文件读取指定的字节数,如果未给定或为负则读取所有。
print("read1\n", f.read())
print("read2\n", f.read())
f.seek(0)
print("read3\n", f.read())
f.seek(50)
# f.readline()读一行
print("f.readline1(): ", f.readline())
# 输出:f.readline1(): これ以上(いじょぅ)なにをうしなえば こころはゆるされるの
print("f.readline2(): ", f.readline())
# 输出:f.readline1(): 还要再失去什么 才能让心得到宽恕?
# 在"r"模式下不能写入,会报错
f.write("abc")
# io.UnsupportedOperation: not writable
# 关闭打开文件
f.close()
# r+读写文件
f = open("testfile", "r+", encoding="utf-8") # 文件名柄
# 打印当前指针所在位置
print(f.tell())
# f.readlines()读取所有行(直到结束符 EOF)并返回列表,碰到结束符 EOF 则返回空字符串。
# print(f.readlines())
print(f.readlines())
# 关闭打开文件
f.close()
2.2 "w"写文件
f = open("testfile", "w", encoding="utf-8")
# f.write()会覆盖原文件内容,若没有该文件,则新创建文件;
# f.write()默认将内容写在文件最后一行,可以加"\n"换行
new_write = f.write("f.write(string) 将 string 写入到文件中并返回写入的字符数。\n输出完成")
print("new_write", new_write)
# 输出:f.write() 46
f.write("歌词名\n")
f.write("one more time, one more chance")
f = open("testfile", "r", encoding="utf-8")
print("f.read(): ", f.read())
# 输出:f.read(): testfile内容
# 在"w"模式下不能读取,会报错
print("f.readline(): ", f.readline())
# io.UnsupportedOperation: not readable
# 关闭打开文件
f.close()
# "a+"
# "a+"默认文件指针放在文件的结尾。读取时,需要将文件指针置于起始位置(0)
f = open("testfile", "a+", encoding="utf-8")
f.write("新加一行")
f.seek(0)
print("检查是否可读:", f.read())
# 关闭打开文件
f.close()
2.3 遍历与打印插入
f = open("testfile", "r+", encoding="utf-8") # 文件名柄
# 直接遍历
print("**********for in **********")
for value1 in f.readlines():
# print("**********for in ********** \n", value1)
print(value1.strip())
# 枚举遍历
# 将指针位置置为起始位置即:0
f.seek(0)
print("**********enumerate**********")
for index, value2 in enumerate(f.readlines()):
# print("********enumerate********** \n", index, value2)
print(index, value2.strip())
# 索引遍历
# 读5行
f.seek(0)
for i in range(5):
print(f.readline())
f.seek(0)
print("**********range(len(f.readlines()))**********")
f_readlines = f.readlines()
for index in range(len(f_readlines)):
# print("********f.readlines()[index]********** \n", index, f.readlines()[index])
print(index, f_readlines[index].strip())
# 列表迭代器
f.seek(0)
print("**********iter(f.readlines())**********")
for value3 in iter(f.readlines()):
# 去掉每行头尾空白
print(value3.strip())
# 关闭文件
f.close()
# 在第10行插入,建议方式
count = 0
for line in f:
if count == 9:
print("---line 10--- ")
continue
print(line)
count += 1
# 在第10行插入,以下读取内容全部放在内存中,耗内存资源,不推荐
for index, i in enumerate(f.readlines()):
if index == 9:
print("----------10------------")
continue
# 去除换行符
print(i.strip())
2.4 f.truncate()函数
- f.truncate()用于截断文件,截断之后 size 后面的所有字符被删除
- 如果指定了可选参数 size,则表示截断文件为 size 个字符。如果没有指定 size,则从起始位置截断,即清空文件内容。
f = open("testfile", "a", encoding="utf-8") # 文件名柄
f.seek(12)
print(f.tell())
f.truncate(0)
# 输出:文件为空
f.truncate(12)
# 输出:これ以上
# f.truncate(12)
f.close()
f = open("testfile2", "wb") # 文件名柄 二进制,二进制没有编码之说
# 使用"rb"二进制的情况,网络传输,视频传输等
# f.write("this is binary file!\n")
# 输出:ValueError: binary mode doesn't take an encoding argument
f.write("this is binary file!\n".encode())
f.close()
2.5 f.flush()
- 刷新缓冲区的,即将缓冲区中的数据立刻写入文件,同时清空缓冲区,不需要是被动的等待输出缓冲区写入。
- 一般情况下,文件关闭后会自动刷新缓冲区,若需要在关闭前刷新它,这时就可以使用 flush() 方法。
>>> f = open("test.test", "w", encoding="utf-8")
>>> f.write("print1")
6
>>> 此时test.test中没有任何数据存在, 数据还在内存中
>>> 将内存中的数据输出到文件中
>>> f.flush()
# flush()使用案例:进度条
import sys
import time
for i in range(10):
# sys.stdout.write("#")输出"#",并返回所打印的字符数
sys.stdout.write("#")
sys.stdout.flush()
time.sleep(0.5)
2.6 修改文件内容
- 保留原文件,创建新的文件,在写入的过程中修改文件内容。
- 无法在原文件中直接修改内容,直接写入会覆盖原文件的内容。相当于将原文件内容清空;
f = open("testfile", "r", encoding="utf-8")
f2 = open("testfile2", "x", encoding="utf-8")
for line in f:
if "曾与你嬉闹的时光啊" in line:
line = line.replace("曾与你嬉闹的时光啊", "曾与你欢笑的时光哟")
f2.write(line)
f.close()
f2.close()
2.7 其他
f = open("testfile", "a+", encoding="utf-8")
# f.fileno()返回一个整型的文件描述符(file descriptor FD 整型),可用于底层操作系统的 I/O 操作。
print("f.fileno()", f.fileno())
# 输出:f.fileno() 3
# f.writelines()用于向文件中写入一序列的字符串。
# 这一序列字符串可以是由迭代对象产生的,如一个字符串列表。换行需要制定换行符 \n。
print("f.writelines('sd')", f.writelines("sd"))
# 输出:f.writelines() None
# 打开文件查看:结尾两个字符为"sd"
# f.isatty()检查文件是否为tty接口
print("f.isatty()", f.isatty())
# 输出:f.isatty() False
# f.newlines检查文件的换行符
print("f.newlines", f.newlines)
# 输出:f.newlines None
# f.readable()检查文件是否可读
print("f.readable()", f.readable())
# 输出:f.readable() True
# f.writable()检查文件是否可写
print("f.writable()", f.writable())
# 输出:f.writable() True
# f.seekable()检查文件指针是否可变更
print("f.seekable()", f.seekable())
# 输出:f.seekable() True
# 查看文件对象属性
# f.name打印文件名
print("f.name", f.name)
# 输出:f.name testfile
# f.buffer用来创建一个专门存放二进制数据的缓存区。
print("f.buffer", f.buffer)
# 输出:f.buffer <_io.BufferedRandom name='testfile'>
# f.closed检查文件是否已关闭
print("f.closed", f.closed)
# 输出:f.closed False
# f.encoding检查文件的字符集
print("f.encoding", f.encoding)
# 输出:f.encoding utf-8
# f.errors检查文件的错误级别
print("f.errors", f.errors)
# 输出:f.encoding utf-8
print("f.line_buffering", f.line_buffering)
# 输出:f.line_buffering False
# f.mode检查文件的打开模式
print("f.mode", f.mode)
# 输出:f.mode a+
f.close()
3 with 语句
with open("testfile", "r", encoding="utf-8") as f:
print("f.readline() in with 语句:", f.readline())
with open("testfile", "r", encoding="utf-8") as f1, \
open("testfile2", "r", encoding="utf-8") as f2:
print("this is f1.name:", f1.name)
print("this is f2.name:", f2.name)
4 编码转换
- Python2 中,默认的编码为ASCII码
- Python3 中,默认的字符编码为Unicode
- 不同编码之间的转换需要先将字符编码decode转换成Unicode,再encode转换为想要的编码
- unicode 分为 utf-32(占4个字节),utf-16(占两个字节)[最常用],utf-8(占1-4个字节),不过在文件里存的还是utf-8,因为utf8省空间
- 在Python3中encode,在转码的同时还会把string 变成bytes类型,decode在解码的同时还会把bytes变回string
import sys
print(sys.getdefaultencoding())
default_code = "你好!"
gb2312_code = default_code.encode("gb2312")
gb2312_2_utf8_code = gb2312_code.decode("gb2312").encode("utf-8")
print("default_code", default_code)
print("gb2312_code", gb2312_code)
print("gb2312_2_utf8_code", gb2312_2_utf8_code.decode("utf-8"))
# 若修改编译器的输出编码格式为GBK,再编译此程序会报错:SyntaxError: Non-UTF-8 code starting with '\xd3' in...
# 由于Python本身的数据类型为Unicode,此时文件编码default_code还是unicode, 需要在文件头声明程序为GBK
# -*- coding: GBK -*-