python学习:文件操作
open('文件名','打开模式',encoding='编码方式')
打开模式有:
- r,只读模式(默认),不可写。
- w,只写模式,不可读。如果文件不存在则创建文件,如果文件存在则删除内容。
- a,追加模式,不可读。如果文件不存在则创建文件,如果文件存在则只追加内容。
”+“表示可同时读写某个文件
- r+,先读后写。可读,可写。
- w+,先写再读。(先将原文件内容删除,然后写入新内容进去,接着读取已写入的内容)
- a+,可写,可读。
”U“表示在读取时,可以将\r\n自动转换成\n。(u只能与r或者r+同时用)
- rU
- r+U
- rbU
- rb+U
"b"表示处理二进制文件(如:FTP发送上传ISO镜像文件,特别是windows操作系统在处理二进制文件时需要注意 ,linux可以不用管)
- rb
- wb
- ab
1 # w,只写模式,不可读 2 f = open("filetest1", "w", encoding="utf-8") 3 f.write("北冥有鱼,其名为鲲,鲲之大,一锅炖不下;\n") 4 f.close() 5 6 # r,只读模式,不可写 7 f = open("filetest1", "r", encoding="utf-8") 8 content = f.read() # read方法会将文件内容都读出来 9 print(content) 10 f.close() 11 12 # a,追加模式,可写,不可读 13 f = open("filetest1", "a", encoding="utf-8") 14 f.write("化而为鸟,其名为鹏,鹏之大,需要两个烧烤架,一个秘制,一个微辣。") 15 content = f.read() # 异常:io.UnsupportedOperation: not readable 16 # print(content) 17 f.close() 18 19 # readlines()方法也会将文件内容全部读取到内存里 20 # readlines()方法的返回值是一个列表,列表的每个元素就是文件的一行内容 21 f = open("filetest","r",encoding="utf-8") 22 for index, line in enumerate(f.readlines()): 23 if index == 4: 24 print("--------华丽分割线--------") 25 continue 26 print(line.strip()) 27 f.close() 28 29 # 上面读文件用到的read()和readlines()方法会将文件的内容全部读出来,如果文件太大,内存将耗尽 30 # 下面的方式只会一行一行的读取,读取效率高,输出结果同read和readlines完全相同 31 f = open("filetest","r",encoding="utf-8") 32 count = 0 33 for line in f: 34 count += 1 35 if count == 5: 36 print("--------华丽分割线--------") 37 continue 38 print(line.strip()) 39 f.close() 40 41 f = open("filetest","r",encoding="utf-8") 42 print(f.tell()) # 获取光标当前的位置 43 print(f.readline()) 44 print(f.tell()) 45 print(f.readline()) 46 f.seek(0) # 设置光标的位置 47 print(f.readline()) 48 f.close() 49 50 # flush: 51 # 强制将数据写入文件。 52 # 如果不使用flush,python自动往缓冲区写数据,缓冲区满后再写入文件并清空缓冲区,这样容易丢数据 53 54 f = open("filetest","a",encoding="utf-8") 55 f.seek(10) # 设置光标位置 56 f.truncate(10) # 截取文件内容。注意:理论上是从第10的位置开始写内容,实际还是从文件的开始截取指定的长促。 57 f.close() 58 59 # 进度条 60 import sys,time 61 62 for i in range(20): 63 sys.stdout.write("#") 64 sys.stdout.flush() # 好像不加这一句也能出效果 65 time.sleep(0.1)
# r+,读写
# 先准备一个文件,写入5行内容 f = open("filetest3", "w", encoding="utf-8") f.write("老夫聊发少年狂,半夜想喝疙瘩汤。\n") f.write("一树梨花压海棠,酸菜白肉氽血肠。\n") f.write("不思量,自难忘,啃上一根大骨棒。\n") f.close() # r+,读写模式 f = open("filetest3", "r+", encoding="utf-8") #以读写模式打开文件 f.readline() f.readline() f.write("---------华丽分割线---------\n") f.seek(0) # 如果不加这一行,下面的read方法是读不到内容的,因为上面write的时候并不是在第2行写入的,而是在内容的最后接着又写入的。 content = f.read() print(content) f.close() 注意文件内容: 理论上,我们先往一个文件中写入了5行内容。然后我们使用r+(读写)模式写读取两行内容,然后write一行内容进去,
理论上我们期望的结果应该如下: 老夫聊发少年狂,半夜想喝疙瘩汤。 一树梨花压海棠,酸菜白肉氽血肠。 ---------华丽分割线--------- 不思量,自难忘,啃上一根大骨棒。 其实,实际结果是如下: 老夫聊发少年狂,半夜想喝疙瘩汤。 一树梨花压海棠,酸菜白肉氽血肠。 不思量,自难忘,啃上一根大骨棒。 ----------华丽分割线--------- 结论:总是在文件的最后追加内容。而不是插入。
# w+,写读
先准备一个文件,写入2行内容 f = open("filetest3", "w", encoding="utf-8") f.write("北冥有鱼,其名为鲲,鲲之大,一锅炖不下;\n") f.write("化而为鸟,其名为鹏,鹏之大,需要两个烧烤架,一个秘制,一个微辣。\n") f.close() # w+,写读模式,会先删掉文件内容,在写入 f = open("filetest3", "w+", encoding="utf-8") # 以写读模式打开文件 f.write("老夫聊发少年狂,半夜想喝疙瘩汤。\n") print(f.tell()) # 48,好像一个汉字和一个标点符号都是占用3个字节 f.write("一树梨花压海棠,酸菜白肉氽血肠。\n") print(f.tell()) # 96,好像一个汉字和一个标点符号都是占用3个字节 f.write("不思量,自难忘,啃上一根大骨棒。\n") print(f.tell()) # 142,但是这里却是142,那么一个汉字和一个标点符号到底是占用几个字节呢?懵逼。。。 f.seek(10) # 这里如果是f.seek(10)就会报错,那以后对中文的文件怎么来处理这个问题呢? print(f.readline()) f.write("---------华丽分割线---------\n") f.seek(0) # 如果不加这一行,下面的read方法是读不到内容的,因为上面write的时候并不是在第2行写入的,而是在内容的最后接着又写入的。 content = f.read() print(content) f.close() 运行结果如下,我们期望在内容中间插入的分割线,同r+一样仍然被写在了文件内容的结尾: 48 96 142 少年狂,半夜想喝疙瘩汤。 老夫聊发少年狂,半夜想喝疙瘩汤。 一树梨花压海棠,酸菜白肉氽血肠。 不思量,自难忘,啃上一根大骨棒。 ---------华丽分割线--------- 如果f.seek(12)改成f.seek(10),会跑出如下异常,应该是编码的问题: Traceback (most recent call last): File "D:/python/study/day03/file_op.py", line 19, in <module> print(f.readline()) File "C:\Program Files (x86)\Python37-32\lib\codecs.py", line 322, in decode (result, consumed) = self._buffer_decode(data, self.errors, final) UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8f in position 0: invalid start byte
解决seek报异常的问题,稍做改动:
# 先准备一个文件,写入2行内容 f = open("filetest3", "w", encoding="utf-8") f.write("北冥有鱼,其名为鲲,鲲之大,一锅炖不下;\n") f.write("化而为鸟,其名为鹏,鹏之大,需要两个烧烤架,一个秘制,一个微辣。\n") f.close() # w+,写读模式,会先删掉文件内容,再写入 f = open("filetest3", "w+", encoding="utf-8") # 以写读模式打开文件 f.write("老夫聊发少年狂,半夜想喝疙瘩汤。\n") pos = f.tell() # 定义一个变量来保存位置 f.write("一树梨花压海棠,酸菜白肉氽血肠。\n") f.write("不思量,自难忘,啃上一根大骨棒。\n") f.seek(pos) # 将光标直接设置到pos的位置 print(f.readline()) f.write("---------华丽分割线---------\n") f.seek(0) # 如果不加这一行,下面的read方法是读不到内容的,因为上面write的时候并不是在第2行写入的,而是在内容的最后接着又写入的。 content = f.read() print(content) f.close() 运行结果如下,我们期望在内容中间插入的分割线,同r+一样仍然被写在了文件内容的结尾: 一树梨花压海棠,酸菜白肉氽血肠。 老夫聊发少年狂,半夜想喝疙瘩汤。 一树梨花压海棠,酸菜白肉氽血肠。 不思量,自难忘,啃上一根大骨棒。 ---------华丽分割线---------
a+,追加读
# 先准备一个文件,写入2行内容 f = open("filetest3", "w", encoding="utf-8") f.write("北冥有鱼,其名为鲲,鲲之大,一锅炖不下;\n") f.write("化而为鸟,其名为鹏,鹏之大,需要两个烧烤架,一个秘制,一个微辣。\n") f.close() # a+,追加读模式, f = open("filetest3", "a+", encoding="utf-8") # 以追加读模式打开文件 f.write("---------华丽分割线---------\n") f.write("老夫聊发少年狂,半夜想喝疙瘩汤。\n") f.write("一树梨花压海棠,酸菜白肉氽血肠。\n") f.write("不思量,自难忘,啃上一根大骨棒。\n") f.seek(0) # 如果不加这一行,下面的read方法是读不到内容的 content = f.read() print(content) f.close() # 运行结果如下,: 北冥有鱼,其名为鲲,鲲之大,一锅炖不下; 化而为鸟,其名为鹏,鹏之大,需要两个烧烤架,一个秘制,一个微辣。 ---------华丽分割线--------- 老夫聊发少年狂,半夜想喝疙瘩汤。 一树梨花压海棠,酸菜白肉氽血肠。 不思量,自难忘,啃上一根大骨棒。
rb
# 文件内容: ''' 北冥有鱼,其名为鲲,鲲之大,一锅炖不下; 化而为鸟,其名为鹏,鹏之大,需要两个烧烤架,一个秘制,一个微辣。 ''' # rb f = open("filetest3", "rb", encoding="utf-8") # 抛出异常 content = f.read() print(content) f.close() 异常如下: Traceback (most recent call last): File "D:/python/study/day03/file_op.py", line 5, in <module> f = open("filetest3", "rb", encoding="utf-8") ValueError: binary mode doesn't take an encoding argument f = open("filetest3", "rb") content = f.read() print(content) # b'\xe5\x8c\x97\xe5\x86\xa5\xe6\x9c\x89\xe9\...\r\n' f.seek(0) ret = f.read().decode('utf-8') print(ret) # 北冥有鱼,其名为鲲,鲲之大,一锅炖不下;... f.close()
wb
# 错误方式一: f = open("filetest3", "wb") f.write("北冥有鱼,其名为鲲,鲲之大,一锅炖不下;\n") # TypeError: a bytes-like object is required, not 'str' f.write("化而为鸟,其名为鹏,鹏之大,需要两个烧烤架,一个秘制,一个微辣。\n") # TypeError: a bytes-like object is required, not 'str' f.close() # 错误方式二: f = open("filetest3", "wb") f.write(b"北冥有鱼,其名为鲲,鲲之大,一锅炖不下;\n") # SyntaxError: bytes can only contain ASCII literal characters. f.write(b"化而为鸟,其名为鹏,鹏之大,需要两个烧烤架,一个秘制,一个微辣。\n") # SyntaxError: bytes can only contain ASCII literal characters. f.close() f = open("filetest3", "wb") f.write("北冥有鱼,其名为鲲,鲲之大,一锅炖不下;\n".encode('utf-8')) f.write("化而为鸟,其名为鹏,鹏之大,需要两个烧烤架,一个秘制,一个微辣。\n".encode()) # 不写具体的编码方式,默认是utf-8 f.close() #写入内容结果: 北冥有鱼,其名为鲲,鲲之大,一锅炖不下; 化而为鸟,其名为鹏,鹏之大,需要两个烧烤架,一个秘制,一个微辣。 f = open("filetest3", "wb") f.write("北冥有鱼,其名为鲲,鲲之大,一锅炖不下;\n".encode('gbk')) f.write("化而为鸟,其名为鹏,鹏之大,需要两个烧烤架,一个秘制,一个微辣。\n".encode('gbk')) f.close() f = open("filetest3", "r",encoding='gbk') print(f.read()) f.close() #写入内容结果: ��ڤ����,����Ϊ��,��֮��,һ��������; ����Ϊ��,����Ϊ��,��֮��,��Ҫ�����տ���,һ������,һ������
上面的几个操作都只能将我们希望在文件内容中间插入的文字追到文件内容的末尾,并不能真正实现插入修改。
那么,我们怎么才能做到“随心所欲”的修改一个文件呢?
with open("filetest", "r", encoding='utf-8') as f,\ open("filetest3", "w", encoding='utf-8') as f_new: line = f.readline() while line: if "不思量,自难忘,啃上一根大骨棒。" in line: line = line.replace("不思量,自难忘,啃上一根大骨棒。","---------华丽分割线---------") f_new.write(line) line = f.readline()
根据输入的内容进行修改,类似shell sed命令:
# 实现简单的shell sed替换功能 import sys arg0 = sys.argv[0] find_str = sys.argv[1] replace_str = sys.argv[2] arg3 = sys.argv[3] print(arg0) print(find_str) print(replace_str) print(arg3) with open("filetest", "r", encoding='utf-8') as f,\ open("filetest3", "w", encoding='utf-8') as f_new: line = f.readline() while line: if find_str in line: line = line.replace(find_str,replace_str) f_new.write(line) line = f.readline() # 关于sys.argv的一点小知识: # sys.argv是一个从程序外部获取参数的桥梁,这个“外部”很关键, 因为我们从外部取得的参数可以是多个,所以获得的是一个列表(list). # sys.argv其实可以看作是一个列表,所以能用[]提取其中的元素。第一个元素是程序本身,随后才依次是外部给予的参数。 # sys.argv[0]就是文件名,随后就是外部依次给予的参数。 # sys.argv需要从程序外面获取参数,所以必须把程序保存成.py文件,然后在外包来执行这个.py文件。比如在windows 命令行执行. # 直接在PyCharm中执行会报错:IndexError: list index out of range。