文件操作介绍
python中的都是用 open() 函数,调用 open() 函数,应用程序会发起系统调用 open(...) ,进而对文件完成操作~。以下示例均在 python3 环境中完成~
读取文件
简单读取
读取文件示例:
f = open(file='/Users/luyi/tmp/abc', mode='r', encoding='utf-8')
data = f.read() # 读取文件中所有数据
print(data) # 打印文件内容
f.close() # 关闭操作系统级打开的文件
open() 函数参数说明:
file:指定文件路径
mode:指定打开文件的模式,r 表示只读模式,还有很多其他模式,下面会依次介绍
encoding:指定从文件中读取的数据使用什么解码标准(decode),解码后以unicode的形式存放到内存中~。注意:若不指定encoding,打开文件的默认编码就是操作系统的默认编码,简体中文版的windows是gbk,linux下是utf-8。以什么编码存放,就应该以什么编码读取~
读取文件操作的注意点: 1)读取动作完成之后,需要关闭操作系统级打开的文件(f.close()) 2)回收应用程序级的变量(del f) Tip:f 变量没有引用之后,python垃圾回收机制会自动回收 f 变量,无需手动进行。但是f.close()必须手动完成,否则会持续占用系统资源,直至程序运行结束~
也有一种方式 不需要手动关闭系统级资源
with open() as f:
pass
# 将上述代码进行调整
with open(file = '/Users/luyi/tmp/abc', mode = 'r', encoding = 'utf-8') as f:
data = f.read()
print(data)
Tip:with段代码运行结束,系统级打开的文件会自动被关闭~
with 还可以同时打开多个文件,如下示例实现了文件的文件的逐行复制,其中涉及到的方法下面会介绍:
with open(file = '/Users/luyi/tmp/abc.txt', mode = 'r', encoding='utf-8') as read_file, open(file = '/Users/luyi/tmp/cde.txt', mode = 'w', encoding='utf-8') as write_file:
for line in read_file:
write_file.write(line)
在读取文件时,若不清楚正在打开的文件是什么编码,可以使用chardet模块探测文件的编码方式
import chardet
result = chardet.detect(open('/Users/luyi/tmp/abc.txt', mode='rb').read())
print(result)
结果输出:
{'encoding': 'utf-8', 'confidence': 0.87625, 'language': ''}
上述示例中,使用 'rb' 模式打开文件,即以只读,且以字节为单位打开文件。非文本文件只能使用 b 模式打开,因为文件本身就是以字节的形式存放在存储设备上的。文本文件可以使用字节模式打开,也可以 以本文模式打开(默认),图片格式的文件(jpg,png...)、视频音频格式文件(mp3、mp4、avi...)则只能以字节模式打开。
当文本文件使用字节模式打开时,open函数中不能使用 encoding 参数,若要转成unicode,只能现将数据读到内存,然后手动decode~
with open(file = '/Users/luyi/tmp/abc.txt', mode = 'rb', encoding = 'utf-8') as f:
print(f.read())
# open中使用 encoding参数,会直接抛出错误信息
ValueError: binary mode doesn't take an encoding argument
#############
with open(file = '/Users/luyi/tmp/abc.txt', mode = 'rb') as f:
data = f.read()
print(data) # 原样输出内容
print(data.decode('utf-8')) # 解码后输出文本内容
输出结果:
b'\xe4\xbd\xa0\xe5\xa5\xbd\xef\xbc\x8ckitty\n'
你好,kitty
循环文件
f = open("abc.txt",'r',encoding="utf-8")
data = f.read()
使用这种方式读取文件,会一次性将文件中所有的数据读到内存中,如果文件很大,这会给内存造成很大的压力,这并不是一种合理的读取文件方式。这时候可以逐行获取数据~
# 使用 readline() 仅读取文本的一行内容,光标从文件的开头移动到一行的末尾(只读一行,遇到\r 或者 \n 为止),然后读物第二行
with open(file = '/Users/luyi/tmp/def.txt', mode = 'r', encoding='utf-8') as f:
data = f.readline() # 仅读取一行
print(data)
# 使用 while 循环遍历文件
with open(file = '/Users/luyi/tmp/def.txt', mode = 'r', encoding='utf-8') as f:
line = f.readline()
while line: # 当 line 不为None,继续读取文件
print(line, end='') # print() 自带换行功能,line中已有'\n',print不用再换行,所以加上参数end=''
line = f.readline()
# 使用 for 循环遍历 f 变量也是逐行读取文件内容,与 readline() 类似。这里其实内部调用了 f 变量的next()方法,逐行迭代文件对象,这种方式的遍历貌似比 readline() 要来的简单明了。
with open(file = '/Users/luyi/tmp/def.txt', mode = 'r', encoding='utf-8') as f:
for line in f:
print(line, end='')
Tip:在调用next()方法时,不能同时调用 tell() 方法获取文件光标位置
和 readline() 功能类似的还有个 readlines() ,readlines()会将文件的内容一次性获取,并存储为列表,文件每一行内容为列表的一个元素~
with open(file = '/Users/luyi/tmp/def.txt', mode = 'r', encoding='utf-8') as f:
line = f.readlines()
print(type(line))
print(line)
结果输出:
<class 'list'>
['1.aaaaaaaaa\n', '2.bbbbbbbbb\n', '3.ccccccccc\n', '4.ddddddddd\n', '5.eeeeeeeee\n', '6.fffffffff\n']
写文件
python写文件,同样使用open(),模式使用 'w'(只写),'wb'(二进制写),'w+'(可读可写)~
直接写
f = open(file = '/Users/luyi/tmp/abc.txt', mode = 'w', encoding = 'utf-8')
f.write('你好~~,hello')
f.close() # 同样需要注意,关闭系统级别的资源
open() 参数说明:
file:指定文件路径,若该目录下文件不存在,会创建,若文件存在,直接覆盖;若目录不存在,抛出错误
mode='w':指定为只写模式
encoding:指定写入到文件时,使用的编码标准,即将 内存中 unicode 格式的数据 按照指定编码标准编码后进行存储(这里是 encoding 过程,和read相反)
同样可以使用 with open() 方式代替:
with open(file = '/Users/luyi/tmp/abc.txt', mode = 'w', encoding = 'utf-8') as f:
f.write('你好!!,hello')
二进制写
二进制写 的模式为 'wb',当指定 mode='wb' ,写入数据时必须传入字节类型的数据(bytes类型),且需要手动添加换行符(\n)
with open(file = '/Users/luyi/tmp/abc.txt', mode = 'wb') as f:
f.write('你好~~,hello'.encode('utf-8'))
Tip:这里由于是'wb'模式,write()函数中需要传入bytes类型的数据,直接使单引号或双引号包含的数据是 str 类型,str 类型的数据 encode 之后,返回的是 bytes类型,或者也可以使用 b'' ~
with open(file = '/Users/luyi/tmp/abc.txt', mode = 'wb') as f:
f.write(b'abc') # bytes 类型只能包含 ASCII 码字符
同时写入多行使用writelines()函数
with open(file = '/Users/luyi/tmp/abc.txt', mode = 'w', encoding='utf-8') as f:
f.writelines(['111111\n', '222222\n', '333333\n']) # 需要自己添加换行符
# wb模式
with open(file = '/Users/luyi/tmp/abc.txt', mode = 'wb') as f:
f.writelines([bytes('你好\n'.encode('utf-8')), 'kitty\n'.encode('utf-8')])
Tip:f.flush() 可立刻将文件内容从内存刷到磁盘 注意点:当以 'w' 、'wb'、'w+'(写读模式,很少用) 模式打开文件时,在打开文件的同时会将文件内容清空~
读写模式
打开文件模式还有读写模式,打开后可进行读写操作,即 mode='r+';
with open(file = '/Users/luyi/tmp/abc.txt', mode = 'r+', encoding='utf-8') as f:
print(f.read())
f.write('你好~~,hello')
追加文件
打开文件时,若使用模式 “a” 或 “ab” ,则只能对文件进行追加,即:在原来内容的尾部追加内容~
with open(file = '/Users/luyi/tmp/abc.txt', mode = 'a', encoding='utf-8') as f:
f.write('aaaaaaa\n')
f.write('vvvvvvv\n')
文件内容:
你好
kitty
aaaaaaa
vvvvvvv
文件操作的各种模式说明
操作文件的模式列举
模式 | 说明 |
---|---|
'r' | 读模式 |
'w' | 写模式 |
'a' | 追加模式 |
'b' | 二进制模式 |
't' | text 模式(默认) |
'+' | 同时读写某个文件 |
'x' | 只写模式,文件不存在 自动创建,文件原先就存在则报错 |
除了上述几个模式,还有以上模式的各种组合~ 常用的模式还有: rb','wb','ab' # 非文本文件,只能使用 'b' 模式打开 'r+','w+','a+' # 都表示可读写,但是注意了 'w+' 模式打开文件,会首先清空文件,所以一般模式 'w+' 很少用,使用模式 'a+' 时,光标会直接跳到文件的最后,所以之前的内容读不到~
针对文件的其他操作
其他文件操作的常用函数:
def writable(self, *args, **kwargs): # real signature unknown
判断文件是否可写
def readable(self, *args, **kwargs): # real signature unknown
判断文件是否可读
def fileno(self, *args, **kwargs): # real signature unknown
返回文件句柄在内核中的索引值,做IO多路复用时可以用到
def seek(self, *args, **kwargs): # real signature unknown
移动光标移到指定位置,注意这里移动光标的单位是字节
def seekable(self, *args, **kwargs): # real signature unknown
判断文件是否可进行 seek 操作
def tell(self, *args, **kwargs): # real signature unknown
返回当前文件操作光标位置
def truncate(self, *args, **kwargs): # real signature unknown
按指定长度截断文件,经个人测试 python3中的 truncate 方法貌似已经失效
在对文件操作的过程中,光标会不断移动,例如readline()方法读取一行信息后,光标会移动至当前行的末尾,writeline()光标也会移动至当前行末尾(写过程貌似光标一直在末尾)~
光标移动的单位和文件被打开的模式相关,若文件以文本模式打开时,read(5) 会使光标向后移动5个字符;若文件以非文本模式打开('b'模式),则 read() 会向后移动5个字节。seek函数不管模式是什么,光标移动的单位都是字节~
例如文本内容如下:
123456789
abcdefghi
code:
with open(file = '/Users/luyi/tmp/abc.txt', mode = 'r+', encoding='utf-8') as f:
f.seek(5)
print(f.readline())
print(f.tell()) # 输出当前光标位置
结果输出:
6789
10
seek 方法可接受2个参数:
fileObject.seek(offset[, whence])
offset:光标的偏移量,以字节为单位 whence:可选参数,默认值为 0。表示要从哪个位置开始偏移;0 代表从文件开头开始偏移,1 代表从当前位置开始偏移,2 代表从文件末尾开始偏移。
.................^_^