1.打开文件
open函数用于打开文件,通过该函数的第1个参数指定要打开的文件名(可以是相对路径,也可以是绝对路径)。
open函数的第2个参数用于指定文件模式(用一个字符串表示)。这里的文件模式是指操作文件的方式,如只读、写入、追加等。
使用open函数打开文件时,默认是读模式,如果要想向文件中写数据,需要通过open函数的第2个参数指定文件模式。
写模式和追加模式的区别:如果文件存在,写模式会覆盖原来的文件,而追加模式会在原文件内容的基础上添加新的内容。
在文件模式中,有一些文件模式需要和其他文件模式放到一起使用,如open函数不指定第2个参数时,默认以读模式打开文本文件,也就是“rt”模式。如果以写模式打开文本文件,需要使用“wt”模式。对于文本文件来说,用文本模式(t)打开文件和用二进制模式(b)打开文件的区别不大,都是以字节为单位读写文件,只是在读写行结束符时有一定的区别。
在上表中,最后一项“+”文件模式,表示读写模式,必须与其他文件模式一起使用,如“r+”、“w+”、“a+”。这三个组合文件模式都可以对文件进行读写操作,它们之间的区别如下:
r+:文件可读写,如果文件不存在,会抛出异常;如果文件存在,会从当前位置开始写入新内容,通过seek函数可以改变当前的位置,也就是改变文件的指针。
w+:文件可读写,如果文件不存在,会创建一个新文件;如果文件存在,会清空整个文件,并写入新内容。
a+:文件可读写,如果文件不存在,会创建一个新文件;如果文件存在,会将要写入的内容添加到原文件的最后。也就是说,使用“a+”模式打开文件,文件指针会直接跳到文件的尾部,如果要使用read方法读取文件内容,需要使用seek方法改变文件指针,如果调用seek(0)会直接将文件指针移到文件开始的位置。
2.操作文件的基本方法
2.1 读文件和写文件
使用open函数成功打开文件后,会返回一个TextIOWrapper对象,然后就可以调用该对象中的方法对文件进行操作。TextIOWrapper对象有如下4个常用的方法。
write(string):向文件写入内容,该函数会返回写入文件的字节数。
read([n]):读取文件的内容,n是一个整数,表示从文件指针指定的位置开始读取的n个字节。如果不指定n,该函数会读取从当前位置往后的所有的字节。该函数会返回读取的数据。
seek(n):重新设置文件指针,也就是改变文件的当前位置。如果使用write函数写入内容后需要调用seek(0)才能读取刚才写入的内容。
close():关闭文件,对文件进行读写操作后,关闭文件是一个好习惯。
f = open('./files/test1.txt','w') # 以 写 模式打开test1.txt文件 print(f.write("I love ")) # 向test1.txt文件中写入“I love ”, 运行结果 7 f.close() # 关闭test1.txt文件 f = open('./files/test1.txt','r') # 以 读 模式打开test1.txt文件 print(f.read(7)) # 从test1.txt文件中读取7字节的数据,运行结果 I love f.close() try: f = open('./files/test2.txt','r+') # 如果test2.txt文件不存在,会抛出异常 except Exception as e: print(e) # a+ f = open('./files/test2.txt', 'a+') # 用追加可读写模式打开test2.txt文件 print(f.write('hello')) # 向test2.txt文件写入"hello", 运行结果 5 f.close(); f = open('./files/test2.txt','a+') print('-----1------') print(f.read()) # 读取向test2.txt文件的内容,由于目前文件指针已经在文件的结尾,所以什么都不会读出来 f.seek(0) # 将文件指针设置到文件开始的位置 print('-----2------') print(f.read()) # 读取文件的全部内容,运行结果 hello f.close(); # w+ try: f = open('./files/test2.txt','w+') # 用写入可读写的方式打开test2.txt文件,该文件的内容会清空 print(f.read()) # 读取文件的全部内容,什么都没读出来 f.write('How are you?') # 向文件写入"How are you?" f.seek(0) # 重置文件指针到文件的开始位置 print(f.read()) # 运行结果 How are you? finally: f.close() # 关闭文件,建议在finally中关闭文件
2.2 管道输出
在Linux 、UNIX、Mac OS X等系统的shell中,可以在一个命令后面写另外一个命令,前一个命令的执行结果将作为后一个命令的输入数据,这种命令书写方式被称为管道,多个命令之间要使用 “|” 符号分隔。
例子: ps aux | grep mysql
在上面的管道命令中先后执行了两个命令,首先执行ps aux命令查看当前系统的进程以及相关信息,然后将查询到的数据作为数据源提供给grep命令,grep mysql 命令表示查询进程信息中所有包含mysql字样的进程。
在Python程序中,可以通过标准输入来读取管道传进来的数据,所以Python命令也可以使用在管道命令中。
# 管道输出 # 从标准输入读取所有的数据,并按行将数据保存到列表中,然后过滤出所有包含“readme”的行,并输出这些行 ''' ls -al ~ :列出home目录中所有的文件和目录。 python demo02.py :从管道接收数据(文件和目录列表),并过滤出所有包含readme的文件和目录。 sort:对过滤结果进行排序。 ''' import sys import os import re # 从标准输入读取全部数据 text = sys.stdin.read() #os.linesep字符串给出当前平台使用的行终止符 files = text.split(os.linesep) # 将字符串形式的文件和目录列表按 行 拆分,然后保存到列表中 for file in files: result = re.match('.*readme.*',file) # 匹配每一个文件名和目录名,只要包含"readme",就符合条件。 if result != None: print(file) # 输出满足条件的文件名和目录名
# 现在切换到控制台,进入demo02.py文件所在的目录,然后执行下面的命令。 ls -al ~ | python demo02.py | sort # 执行上面的命令,根据home目录中的具体内容,会输出不同的结果。
2.3 读行和写行
读写一整行是纯文本文件最常用的操作,尽管可以使用read和write方法加上行结束符来读写文件中的整行,但比较麻烦。因此,要读写一行或多行文本,建议使用readline方法、readlines方法和writelines方法。注意:并没有writelines方法,写一行文本需要直接使用write方法。
readline方法用于从文件指针当前位置读取一整行文本,也就是说,遇到行结束符停止读取文本,但读取的内容包含行结束符。
readlines方法从文件指针当前的位置读取后面所有的数据,并将这些数据按行结束符分隔后,放到列表中返回。
writelines方法需要通过参数指定一个字符串类型的列表,该方法会将列表中的每一个元素值作为单独的一行写入文件。
# 读行与写行 import os f = open('./files/urls.txt', 'r+') # 以读写模式打开urls.txt文件 url = '' # 保存当前读上来的文本 while True: url = f.readline() # 从urls.txt文件读一行文本 url = url.rstrip() # 将最后的行结束符去掉 if url == '': # 当读上来的是空串,结束循环 break; else: print(url) # 输出读上来的行文本 print('--------------') f.seek(0) # 将文件指针重设置为0 print(f.readlines()) # 读urls.txt文件中的所有行 f.write('http://baidu.com' + os.linesep) # 向urls.txt文件中添加一个新行 f.close() # 关闭文件 f = open("./files/urls.txt", 'a+') # 使用“a+模式”再次打开urls.txt文件 # 定义一个要写入urls.txt文件的列表 urlList = ['https://google.com' + os.linesep,'https://jd.com' + os.linesep] f.writelines(urlList) # 将urlList写入urls.txt文件 f.close() # 关闭urls.txt文件
结果
https://geekori.com https://geekori.com/que.php http://ningedu.com http://baidu.com http://baidu.com http://baidu.com https://google.com https://jd.com http://baidu.com -------------- ['https://geekori.com\n', 'https://geekori.com/que.php\n', 'http://ningedu.com\n', 'http://baidu.com\n', 'http://baidu.com\n', 'http://baidu.com\n', 'https://google.com\n', 'https://jd.com\n', 'http://baidu.com\n', '\n', 'https://google.com\n', '\n', 'https://jd.com\n', '\n', 'http://baidu.com\n', '\n', 'https://google.com\n', '\n', 'https://jd.com\n', '\n'] Process finished with exit code 0
3.使用FileInput对象读取文件
如果需要读取一个非常大的文件,使用readlines函数会占用太多内存,因为该函数会一次性将文件所有的内容都读到列表中,列表中的数据都需要放到内存中,所以非常占用内存。
解决方法:
方法1. 可以使用for循环和readline方法逐行读取
方法2. 可以使用fileinput模块中的input函数读取指定的文件。
input方法返回一个FileInput对象,通过FileInput对象的相应方法可以对指定文件进行读取,FileInput对象使用的缓存机制,并不会一次性读取文件的所有内容,所以比readlines函数更节省内存资源。
# 使用FileInput对象读取文件 # readlines import fileinput fileobj = fileinput.input('./files/urls.txt') # 使用input方法打开urls.txt文件 print(type(fileobj)) # 输出fileobj的类型 print(fileobj.readline().rstrip()) # 读取urls.txt文件第1行 for line in fileobj: # 通过for循环输出urls.txt文件的其它行 line = line.rstrip() if line != '': # 如果file不等于空串,输出当前行号和内容 print(fileobj.lineno(),':',line) else: # 输出当前正在操作的文件名 print(fileobj.filename()) # 必须在第一行读取后再调用,否则返回None # 注意:filename方法必须在第1次读取文件内容后调用,否则返回None