1、打开与关闭
1.1、open() close()
我们使用 open() 函数打开文件。这个函数将返回一个文件对象,我们对文件的读写都将使用这个对象。
open() 函数需要三个参数,第一个参数是文件路径或文件名,第二个是文件的打开模式,第三个是编码格式。模式通常是下面这样的:
"r",以只读模式打开,按字符读,也就是rt模式
"w",以写入模式打开,如果文件存在将会清空所有内容,然后写入
"a",以追加模式打开,写入到文件中的任何数据将自动添加到末尾
"b",以二进制的方式打开
r+:读文件并在文件最后进行追加内容
w+:文件有可读可写权限
rb:以二进制格式进行读,可用于在网络中传输。例如从gbk的windows系统中传递utf-8的linux系统就不需要编码了,直接解码就可以,效率上和r没啥区别,按字节读
wb:以二进制格式进行写,并且需要指定编码格式
如果用二进制方法读写,就不需要指定编码格式了
默认的模式为只读模式,也就是说如果你不提供任何模式,open()函数将会以只读模式打开文件。
f = open('1.txt', 'wb')
f这个变量称为文件句柄,一般命名为f,f1,fh,file_handle等。
坑:
当文件路径是'C:\Users\i\Desktop\1.txt'时会报错
原因:文件路径中含有\n、\U、\t时会认为是一个转义符
解决方法:1、推荐路径前加r,写成r'C:\Users\i\Desktop\1.txt'
2、再加一个\,写成'C:\\Users\i\Desktop\1.txt'
3、\换成/
f.tell() 显示光标目前所在的位置,按字节计算,不是字符
f.seek(20)按字节查找,光标从第20个字节开始,其中1个汉字占3个字节
f.truncate(100)截取从文档最开始到第100个字符串,且只能从最头开始截取不能从中间截取,且只能以a或r+模式打开文件
f.flush()强制刷新硬盘,例如在f.write('1')时如果没有f.close()则不会立刻写入硬盘,这时可以使用flush()方法强制写入硬盘,一般用于日志实时显示时用。
f.seek(参数1, 参数2): 参数1表示移动几个字节(注意不是字符),参数2表示参照物(0表示文件开头,1表示当前光标位置,2表示文件结尾)
当程序执行结束后,我们需要关闭文件,如果不关闭会持续占用一些内存和操作系统资源,不关闭的文件也有可能造成数据丢失。
我们使用方法 close() 完成这个操作,重复关闭不会有任何影响:
file.close()
1.2 with语句
在实际情况中,我们应该尝试使用 with 语句处理文件对象,它会在文件用完后会自动关闭,就算发生异常也没关系。它是 try-finally 块的简写:
with open('/etc/protocols') as file:
count = 0
for line in file:
count += 1
print(count)
结果为:158
这个程序中我们将打印文件的行数,可以看到代码块中并没有使用 close,但当代码执行到 with 代码块之外时,文件会被自动关闭。
2、读取文件内容(read()、read(n)、readline()、readlines()、for循环)
此处我们创建一个文件test.txt,这个文件的内容包括两行:
Hello
I love Python
2.1、read()
使用read()可以一次性读取整个文件的内容到字符串:
f1 = open('1.txt',encoding='utf-8', mode='r') #这里1.txt和python程序在同一个路径下,所以只写了相对路径
content = f1.read()
print(content)
f1.close()
结果为:
Hello
I love Python
当然也可以使用 with,避免忘记了 close:
filename = '/home/test.txt'
with open(filename) as file:
file.read()
2.2、read(size)
read(size)有一个可选的参数size,用于指定字符长度,不是字节长度。如果没有指定size或者指定为负数,就会读取并返回整个文件。当文件大小为当前机器内存两倍时,就会产生问题。反之,会尽可能按比较大的size读取和返回数据。
f1 = open('1.txt',encoding='utf-8', mode='r')
content = f1.read(10)
print(content)
f1.close()
结果为:
Hello
I l
项目开发中,我们需要谨慎使用read()读取整个文件,因为有可能你的系统内存并不足够存储整个文件的内容。当read()执行后,再次执行将不会有任何内容的输出。
2.3、readline()
在处理文本文件的时候,我们通常会采用逐行处理,readline()就是用来每次读取文件的一行
filename = '1.txt'
f1 = open(filename,encoding='utf-8', mode='r')
content = f1.readline()
print(content)
content = f1.readline()
print(content)
f1.close()
结果为:
Hello
I love Python
2.4、readlines()
readlines()可以读取所有行,但不同于read(),这个函数的返回的是一个列表,列表中每个元素都是对应文本文件中一行内容的字符串:
filename = '1.txt'
f1 = open(filename,encoding='utf-8')
content = f1.readlines()
print(content)
f1.close()
['\ufeffHello\n', 'I love Python']
-------------------------------------------------------
延伸
1、发现读txt文件时最前面多了一个ufeff,当编码格式改成utf-8-sig时就正常
f1 = open(filename,encoding='utf-8-sig')
utf-8与utf-8-sig两种编码格式的区别:
As UTF-8 is an 8-bit encoding no BOM is required and anyU+FEFF character in the decoded Unicode string (even if it’s the firstcharacter) is treated as a ZERO WIDTH NO-BREAK SPACE.
UTF-8以字节为编码单元,它的字节顺序在所有系统中都是一样的,没有字节序的问题,也因此它实际上并不需要BOM(“ByteOrder Mark”)。但是UTF-8 with BOM即utf-8-sig需要提供BOM。
2、打开文件时with open(filename, mode='r', encodint='utf-8) as f1:
如果打开文件的方式写在filename后可以省略mode=,直接写'r'或'w',如果写在编码格式后面,就不能简写了,必须写成mode='r'
--------------------------------------------------------
2.5、for循环遍历文件句柄
你可以for循环遍历文件句柄来读取文件中的每一行
filename = '1.txt'
f1 = open(filename,encoding='utf-8')
content = f1.readlines()
for i in content:
print(i, end='')
或print(i.strip())
f1.close()
结果为:
Hello
I love Python
read() readline() readlines()的区别
read()是以字符串形式显示所有内容
readline()是以字符串形式每次显示一行内容,运行多次可逐行显示
readlines()是以列表的形式显示所有内容
对于大文件推荐用for循环读文件,例子:
写一个程序,这个程序接受用户输入的字符串作为将要读取的文件的文件名,并且在屏幕上打印文件行数和文件内容:
filename = input("Enter the file name: ")
with open(filename) as file:
count = 0
for line in file:
count += 1
print(line)
print('Lines:', count)
运行程序:
Enter the file name: /home/test.txt
Hello World
I love Python
Lines: 2
3、写入文件
3.1、mode='w'写入模式
最常用的写入文件的方法是 write(),通过write()方法打开一个文件然后我们随便写入一些文本。
filename = '1.txt'
with open(filename, encoding='utf-8',mode='w') as file:
file.write('testline1')
file.write('testline2')
这个程序中,我们将文件以'w'模式打开,然后写入两段内容。
['testline1testline2']
这时候发现文件中原来的内容已经被完全覆盖了,并且写入的内容占了一行(因为没有写入换行符的原因)。
可见w这种模式是将文件先清空,再写入
如果文件不存在,会先创建空文件,再写入
3.2、mode='a'追加模式
如果我们想向文件中增加内容如何操作呢?可以使用 'a' 追加模式打开文件:
filename = '/home/shiyanlou/test.txt'
with open(filename, mode='a') as file:
file.write('testline3')
file.write('testline4')
再次读取,可以看到新增加的字符串附加到了原来的内容后面:
['testline1testline2testline3testline4']
with open(filename,mode='a') as file:
file.write(str+'\n')
在写入参数str后加“\n”则会在每次完成写入后,自动换行到下一行,下次写入时便会在下一行写入
4、例子
例子1:更改文件中的内容,将haha改为Python
import os
file = 'G:/python/1.txt'
file_new = 'G:/python/1_new.txt' with open(file,mode='r',encoding='utf-8') as f:
with open(file_new,mode='w',encoding='utf-8') as f_new:
for line in f:
if 'haha' in line:
line = line.replace('haha','Python')
f_new.write(line) os.remove('G:/python/1.txt')
os.rename('G:/python/1_new.txt','G:/python/1.txt')
同时打开两个文件可以写成
with open(file,mode='r',encoding='utf-8') as f,open(file_new,mode='w',encoding='utf-8') as f_new:
或写成
with open(file,mode='r',encoding='utf-8') as f,\
2 open(file_new,mode='w',encoding='utf-8') as f_new:
如果想要拷贝一个图片或音视频文件,就需要用二进制方法打开,用rb和wb
with open('1.jpg', 'rb') as file_1:
with open('2.jpg', 'wb') as file_2:
for i in file_1:
file_2.write(i)
例子2 :利用命令行参数进行操作
import sys,os
file = sys.argv[1]
old_str = sys.argv[2]
new_str = sys.argv[3]
new_file = 'g:/python/1_new.txt'
with open(file,mode='r',encoding='utf-8') as f,open(new_file,mode='w',encoding='utf-8') as f_new:
for line in f:
if old_str in line:
line = line.replace(old_str,new_str)
f_new.write(line)
os.remove(file)
os.rename(new_file,file)
在命令行里输入:
python test.py g:/python/1.txt Python haha
将Python替换成haha
获取sys.args的第2个参数和第3个参数也可以写成下面这样:
_, old_str, new_str = sys.argv
例子3:实现tail -f的效果
通过代码实现tail -f access.log不断读取文件更新内容的效果
import time
with open('access.log', 'rb') as f:
f.seek(0,2) #将光标移动到文件末尾
while True:
line = f.readline()
if line:
print(line.decode(), end='')
else:
time.sleep(0.05)
必须用二进制b的模式打开,因为seek的第二个参数如果
- 为0时(文件开头为参照点),可以用r或rb模式
- 为1(当前光标位置为参照点)或2(文件末尾为参照点)时,用r模式打开会报错,必须用rb模式打开
- r模式默认就是rt模式,也就是用文本模式打开
5、os.path 文件与文件夹操作
在这里简单介绍下 os.path 这个非常常用的标准库,这个库主要的用途是获取和处理文件及文件夹属性。
下面代码举例介绍几个常用的方法,更多的内容在使用到的时候查阅文档。
os.path.abspath(path) 返回文件的绝对路径
os.path.basename(path) 返回文件名
os.path.dirname(path) 返回文件路径
os.path.isfile(path) 判断路径是否为文件
os.path.isdir(path) 判断路径是否为目录
os.path.exists(path) 判断路径是否存在
os.path.join(path1[, path2[, ...]]) 把目录和文件名合成一个路径
实验代码内容,需要在 Python 交互环境中操作:
需要先导入os模块
>>> import os
>>> filename = '/home/1/test.txt'
>>> os.path.abspath(filename)
'/home/1/test.txt'x
>>>
>>> os.path.basename(filename)
'test.txt'
>>> os.path.dirname(filename)
'/home/1'
>>>
>>> os.path.isfile(filename)
True
>>>
>>> os.path.isdir(filename)
False
>>> os.path.exists(filename)
True
>>> os.path.join('/home/1', 'test.txt')
'/home/1/test.txt'
>>>