python文件处理
读取
1 2 3
| f = open(file='xxx.txt',mode='r',encoding='utf-8') data = f.read() f.close()
|
- file 是目标文件
- mode 代表文件操作模式 r意思是只读
- encoding 是以xx编码读取文件
注意:
- 读取文件的编码方式和文件存储时的编码要一致
- 如果不传递encoding,在python3里默认utf-8
1
| 如果文件是gbk的形式存储的,那么读取时如果encoding='utf-8'就会报错
|
二进制模式
如果我不知道文件的编码也想把内容读取进来,你可以使用二进制模式
把这段内容直接以二进制的形式读取进来,不进行按照它的编码方式编码
主要用来视频/图片/文件传输
1 2 3
| f = open(file='xxx.txt',mode='rb',encoding='utf-8') data = f.read() f.close()
|
智能检测编码的工具
需要手动安装工具包
1 2 3 4 5 6
| f = open(file='xxx.txt',mode='rb') data = f.read() f.close() print(chardet.detect(data)) # 输出一个字典显示 改二进制对应的编码 {'encoding': 'gb2312', 'confidence': 0,8321312312, 'language': 'chinese'}
|
read()的缺陷
一次性把文件读取到内存,如果文件3G呢?
循环文件(一次读一部分)
1 2 3 4 5 6
| f = open(file='xxx.txt',mode='r',encoding='utf-8')
for line in f: print(line)
f.close()
|
写文件
普通写入
1 2 3
| f = open(file='xxx.txt',mode='w',encoding='gbk') f.write("你好!!!") f.close()
|
二进制模式写入
1 2 3
| f = open(file='xxx.txt',mode='wb') f.write("你好!!!".encode()) # encode默认utf-8 f.close()
|
mode=’w’每次都会创建一个新文件,如果已经存在就覆盖了
同一文件不想每次都覆盖==>追加模式
1 2 3
| f = open(file='xxx.txt',mode='ab') f.write("你好!!!".encode()) # encode默认utf-8 f.close()
|
混合操作文件
既能写又能读的模式
- r+ 读写模式—>先读后写
- w+ 写读模式—>先创建然后读取(先把文件覆盖,然后读取新写入的内容)(几乎用不到)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 假设文件里有内容 f = open('info.txt','r+',encoding='gbk') print(f.read()) f.write('\n何大宝 哈哈 11111111111') f.write('\n何大宝 哈哈 11111111111') f.write('\n何大宝 哈哈 11111111111') f.write('\n何大宝 哈哈 11111111111') print('````````````````') print(f.read()) # 为什么这次的内容是空的 f.close()
详解: 文件读取的时候会有一个光标 1. 第一次read()的时候全部读出来 光标移动到读取内容末尾 2. write的时候 光标移动到写入内容的后面 3. 第二次read()的时候 由于光标后面没有任何东西,所以为空
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| 假设文件里有内容 f = open('info.txt','w+',encoding='gbk') print(f.read()) # 为什么这次的内容是空的 f.write('\n何大宝 哈哈 11111111111') f.write('\n何大宝 哈哈 11111111111') f.write('\n何大宝 哈哈 11111111111') f.write('\n何大宝 哈哈 11111111111') print('````````````````') print(f.read()) # 为什么这次的内容也是空的 f.close()
详解: 0. 写读模式打开--》创建这个文件如果已经存在就覆盖了 1. 第一次read() 文件是新建的本来就是空的 2. write的时候 光标移动到写入内容的后面 3. 第二次read()的时候 由于光标后面没有任何东西,所以为空
最没用模式---------几乎用不到
|
文件操作其他方法
- fileno() 网络编程会用,返回一个数字
- flush() 强制把文件buffer里(内存里)的内容写入到文件里
- readable() 是否可读
- readline() 每次读一行
- seek() 设置光标的位置 (下次读的时候从这个位置开始)
- tell() 返回光标的位置
- seekable() 判断文件是否可以seek操作 比如终端命令行也是一个文件就不允许seek
- writeable() 判断是否可写
- truncate() 从指定位置(光标)截断文件
flush功能
1 2 3 4 5 6 7 8 9 10
| f = open('info.txt','w') f.write('aa') f.write('aa') f.write('aa')
# ....只要你不 f.close() 写入的内容就在 内存里也就是缓存里 # 因为频繁写入文件的话很耗性能 # flush是什么鬼呢? # 如果你写的内容非常重要 必须确保每次都write的时候写入到文件里,就用flush f.flush() # 此时就算你不f.close()也可以在存盘
|
tell和seek的坑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| # 假设文件内容是 'hello world'
f = open('info.txt','r',encoding='gbk') f.tell() # 0 f.seek(3) f.readline() # lo world ------------------------------------------------ # 假设文件内容是 '路飞学城' f = open('info.txt','r',encoding='gbk') f.seek(3) f.readline() # 报错 decode error ----------------------------------------------- # 验证为什么报错 # 假设文件内容是 '路飞学城' f = open('info.txt','r',encoding='gbk') f.seek(0) f.readline() # '路飞学城' 没问题啊??? ----------------------------------------------- # 验证为什么报错 # 假设文件内容是 '路飞学城' f = open('info.txt','r',encoding='gbk') f.seek(2) f.readline() # 报错 decode error 为啥还报错!!! ----------------------------------------------- # 验证为什么报错 # 假设文件内容是 '路飞学城' f = open('info.txt','r',encoding='gbk') f.read(1) # 路 f.tell() # 2 读了一个汉字 为什么走俩,我猜可能是因为gbk里汉字占俩字节 f.read() # 飞学城 ----------------------------------------------- # 验证utf-8汉字是否会 移动三个光标? # 假设文件内容是 '路飞学城' f = open('info.txt','r',encoding='utf-8') f.read(1) # 路 f.tell() # 3 事实证明,结论是对的 f.read() # 飞学城
|
结论
- 无论seek 还是 tell 它们找的都是字节
- read(1) 是读一个字符
truncate
1 2 3 4 5 6 7 8 9
| # 假设文件内容是 '路飞学城' f = open('info.txt','r',encoding='utf-8') f.truncate() f.flush() # 此时文件是空的 ---------------------------------- # 假设文件内容是 '路飞学城' f = open('info.txt','r',encoding='utf-8') f.truncate(6) f.flush() # 此时文件是 '路飞' 代表从头开始截取6个字节
|
文件修改
实际是不能直接像word那样修改文件内容的,因为word是把所有内容读到内存里。
用光标也不靠谱:因为 比如seek的时候 张三 变成 哈尔滨 这样张三后面的内容不会让出位置,而是覆盖。
变通方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import os
f_name = "info.txt" f_new_name = "%s.new"%f_name
old_str = '张三' new_str = '哈尔滨'
f = open(f_name,"r",encoding='utf-8') f_new = open(f_new_name,"w",encoding='utf-8')
for line in f: if old_str in line: line = line.replace(old_str,new_str)
f_new.write(line)
f.close() f_new.close()
os.rename(f_new_name,f_name)
|