单一模式
读文件
以下有两种方式来读取文件内容,一种是rb模式,一种是r模式,两种模式都是只读模式。
示例1
f = open(file='$path', mode = 'r', encoding='utf-8')
# open()方法,表示打开文件,部分参数如下
# path 表示文件路径
# mode表示文件打开方式,r表示以只读方式打开
# encoding表示将硬盘上的二进制以什么编码方式来读取文件的实际编码方式)
data = f.read()
# 表示读取所有内容,内容是已经转换完毕的字符串
f.close()
# 表示关闭文件
tips:关于编码相关问题,①此处的encoding必须和文件在保存时设置的编码一致,不然可能因为编码问题导致乱码②目前猜测是和系统一致,如果是GBK的系统,那么python解释器的默认编码是GBK,其他同理
示例2
f = open(file='$path', mode='rb')
data = f.read()
f.close
tips:这种模式打开的文件不能设置encoding参数,否则会报ValueError错误,如下:
Traceback (most recent call last):
File “”, line 1, in
ValueError: binary mode doesn’t take an encoding argument
对于示例2来说,以rb模式打开文件就是二进制模式,数据读进内存就是bytes格式,比如原文件内容是’你好’,读进内存中使用read()方法显示出来是:b'\xe4\xbd\xa0\xe5\xa5\xbd'
,常用于网络传输或者图片等,如果想直观的查看内容,需要手动decode(),所以不需要指定编码。但是如果不知道文件编码方式但是又想读取文件,也可以使用该方法,但是如果又想查看内容,可以引用第三方模块来查看。
python解释器调试:
>>> import chardet
>>> f = open(file='abc.txt', mode='rb')
>>> data = f.read()
>>> data
b'\xe4\xbd\xa0\xe5\xa5\xbd'
>>> result = chardet.detect(data)
>>> print(result)
{'encoding': 'utf-8', 'confidence': 0.7525, 'language': ''}
结果显示是一个字典,encoding代表的是猜测的编码类型,confidence是可信度(越接近于一越可信),language代表的是语言类型。
注意:
- 文件操作时,以’r’或者’rb’模式打开,只能读,无法执行写操作
- 硬盘上保存的文件都是某种编码的010101,打开时需注意(r和rb的区别):
- rb,直接读取文件保存时原生的二进制,在Python中用字节表示
- r,读取硬盘的二进制,并按照encoding指定的编码格式进行‘断句’,再将断句后的二进制转成unicode的二进制,在Python中用Unicode/字符串类型
循环读取文件
以上方法都是一次性读取所有文件内容,如果文件太过,会非常占用内存,所以可以按照行来获取文件内容。
方法1
python解释器:
>>> f = open(file='abc.txt', mode='r', encoding='utf-8')
>>> for line in f:
... print(line)
...
你好
Python
方法2
python解释器:
>>> f = open(file='abc.txt', mode='r', encoding='utf-8')
>>> flag = True
>>> while flag:
... line = f.readline()
... if(line != ''):
... print(line)
... else:
... flag = False
...
你好
Python
能够看出来这两种方法在每输出一行内容之后,会输出一个空行,这是因为首先print函数默认会输出一个\n,文件中每行内容结尾也有一个\n,所以导致每次输出每行内容之后就有一个空行。
read(),readline()和readlines()对比
read()方法每次读取整个文件,通常是将文件内容保存到一个变量中,在文件较大时非常占用内存。
readline()在可用内存空间小于文件内容的时候使用该方法,该方法是每次读取一行,通常情况下比readlines()要慢。
readlines()也是一次读取整个文件,之后返回一个列表,该列表可以使用python的for…in…循环结构来进行处理,类似于上述方法的方法1。
写文件
示例1
python解释器:
>>> f = open(file='abc.txt', mode='r', encoding='utf-8')
>>> f.read()
'你好\nPython'
>>> f.close()
>>> f = open(file='abc.txt', mode='w', encoding='utf-8')
>>> f.write('我好')
2
>>> f.close()
>>> f = open(file='abc.txt', mode='r', encoding='utf-8')
>>> f.read()
'我好'
>>> f.close()
示例2
格式:
>>> >>> f = open(file='abc.txt', mode='r', encoding='utf-8')
>>> f.read()
'我好'
>>> f.close()
>>> f = open(file='abc.txt', mode='r', encoding='utf-8')
>>> f.read()
'你好\nPython'
>>> f.close()
>>> f = open(file='abc.txt', mode='wb')
>>> f.write('我好'.encode('utf-8')) # 因为是字节模式,所以需要将写入内容按照指定编码方法进行编码
6
>>> f.close()
>>> f = open(file='abc.txt', mode='r', encoding='utf-8')
>>> f.read()
'我好'
>>> f.close()
注意:
- 文件操作时,以’w’或者’wb’模式打开,只能写,无法执行读操作,并且如果目标文件存在,会清除文件内容,如果文件不存在,会创建新文件。
- 硬盘上保存的文件都是某种编码的010101,写入时需注意(w和wb的区别):
- wb,写入时需要直接传入以某种编码的二进制,即:字节类型
- w,写入时需要传入unicode字符串,内部会根据encoding制定的编码将unicode字符串转换为该编码的二进制
文件追加
原文件内容
你好
Python
代码示例:
python解释器:
>>> f = open(file='abc.txt', mode='a', encoding='utf-8')
>>> f.write('\n我好')
2
>>> f.close()
追加之后文件内容:
你好
Python
我好
注意:
- 文件操作时,以’a’或者’ab’模式打开,只能追加
- 硬盘上保存的文件都是某种编码的010101,写入时需注意(w和wb的区别):
- wb,写入时需要直接传入以某种编码的二进制,即:字节类型
- w,写入时需要传入unicode字符串,内部会根据encoding制定的编码将unicode字符串转换为该编码的二进制
混合模式/复合模式
读写模式
示例
>>> f = open(file='abc.txt', mode='r+', encoding='utf-8')
>>> data = f.read()
>>> print(data)
你好
Python
>>> f.write('我好')
2
>>> f.read() # 1
''
>>> f.seek(0) # 2
0
>>> f.read() # 3
'你好\nPython我好'
上述代码中
1.这里结果为空时因为之前已经读取过该文件,为了标记文件读到哪,会有一个标记或者记录光标位置,执行read()操作之后,光标位置已经移到文件末尾,虽然之后又write()操作,但是光标又随着写的内容而移到最后,所以再次执行read(),会读取不到任何内容。
2.这个方法是重新设定光标位置,需要注意的是seek()方法中的位置是按照字节来论的,我这里是将位置挪到了文件开头。
3.这里结果为空时因为seek()方法光标位置移到最前面,所以能再次读取到数据。
这种模式下,追加的内容视光标的位置而定,光标的位置在哪,就覆盖在哪一部分,如果是在末尾,那么就会追加内容在文件末尾。
写读模式
python解释器:
>>> f = open(file='abc.txt', mode='w+', encoding='utf-8')
>>> f.read()
''
>>> f.write('添加内容:我好\n')
8
>>> f.write('添加内容:大家好\n')
9
>>> f.seek(0)
0
>>> print("content", f.read())
content 添加内容:我好
添加内容:大家好
>>> f.close()
这个示例可以看出如果以写读模式打开文件,那么文件会先创建或清空文件,然后可以读取新增的内容,文件之前的内容无法获取。
指定位置修改
以上写模式或者读写亦或者写读模式,对文件修改无法达到预期目标,预期的目标是可以像记事本或者word文档,可以随意的修改任何位置的内容。
如果想要修改任意位置的内容,可以利用seek()方法修改光标位置,进行内容修改,但是这样同时会覆盖之后的内容,也有瑕疵,这种现象的出现时因为硬盘机制导致的,无法避免,下面介绍两种方法来迂回解决这个问题(如果有好的方法,欢迎各位指点,多谢)。
方法1
既然硬盘存储机制导致修改比较复杂,那么我们可以将其全部加载到内存中,这样在修改好之后重新写入到文件既可达到想要的目的,但是这样在遇到文件特别大的时候会比较占内存。
import os
file_name = '测试.txt'
update_file = open(file_name, 'r+', encoding='utf-8')
data = update_file.read()
data = data.replace('哈尔滨', '天津').replace('北京', '北')
update_file.truncate(len(data))
update_file.seek(0)
update_file.write(data)
update_file.close()
注意:这种方法需要注意,如果将内存中的数据覆写到原文件,如果字符数不一致,会导致文件末尾有预期外的数值出现,所以可以执行truncate()方法处理掉后面的数据。
方法2
可以将部分文件内容加载到内存中,修改之后写入到新的文件,之后全部修改完成之后,将新的文件重命名来覆盖掉旧的文件,这样的方法会比较占硬盘,需要注意的是由于系统不一样,在windows上重命名,如果文件已经存在会无法覆盖,需要删除旧文件,在mac上如果文件已经存在,则会覆盖掉旧文件。
import os
file_name = '测试.txt'
file_new_name = 'new_%s' % file_name
read_f = open(file_name, 'r', encoding='utf-8')
write_f = open(file_new_name, 'w', encoding='utf-8')
for line in read_f:
if '北京' in line:
line = line.replace('北京', '天津')
write_f.write(line)
read_f.close()
write_f.close()
os.rename(file_new_name, file_name)
file对象的其他方法
方法名 | 作用 |
---|---|
fileno | 返回文件句柄在内核中的索引值 |
flush | 把文件从内存buffer里强制刷新到硬盘 |
readable | 判断是否可读 |
readline | 只读一行,遇到\r or \n为止 |
readlines | 只读一行,遇到\r or \n为止 |
seek | 把操作文件的光标移到指定位置 |
seekable | 判断文件是否可进行seek操作 |
tell | 返回当前文件操作光标位置 |
truncate | 按指定长度截断文件[不指定长度的话,就从当前位置到文件尾部的内容全去掉] |
writable | 判断文件是否可写 |