第十三章 文件和流

 
其实真正有价值的是让Python程序处理来自其他程序的数据,并存储和读取这些数据。

13.1 打开文件

open函数用于打开文件,通过该函数的第1个参数指定要打开的文件名(可以是相对路径,也可以是绝对路径)。

f = open('test.txt ')
f = open('./files/ test.txt')

如果使用open 函数成功打开文件,那么该函数会返回一个TextIOWrapper对象,该对象中的方法可用来操作这个被打开的文件。如果要打开的文件不存在,则抛出FileNotFoundError异常。
在这里插入图片描述
open函数的第2个参数用于指定文件模式(用一个字符串表示)。这里的文件模式是指操作文件的方式,如只读、写入、追加等。

python3支持的常用文件模式

文件模式描述
'r'读模式(默认值)
'w'写模式
'x'排他的写模式(只能自己写)
'a'追加模式
'b'二进制模式(可添加到其他模式中使用)
't'文本模式(默认值,可添加到其他模式中使用)
'+’读写模式(必须与其他文件模式一起使用)
 

写模式和追加模式的区别是如果文件存在,写模式会覆盖原来的文件,而追加模式会在原文件内容的基础上添加新的内容

在文件模式中,有一些文件模式需要和其他文件模式放到一起使用,如open函数不指定第2数时默认以读模式打开文本文件,也就是 ‘rt’ 模式。如果要以写模式打开文本文件,需要使用 ‘wt’ 模对于文本文件来说,用文本模式(t)打开文件和用二进制模式(b)打开文件的区别不大,都是以节为单位读写文件,只是在读写行结束符时有一定的区别。

如果使用文本模式打开纯文本文件,在读模式下,系统会将’\n’作为行结束符,对于UNIX、Mac OSX这样的系统来说,会将 ‘\n’ 作为行结束符,而对于Windows来说,会将 ‘\r\n’ 作为行结束符,还有的系统会将 ‘\r’ 作为行结束符。对于 ‘\r\n’ 和 ‘\r’ 这样的行结束符,在文本读模式下,会自动转换为 ‘\n’,而在进制读模式下,会按原样读取,不会做任何转换。在文本写模式下,系统会将行结束符转换为OS对应的行结束符,如Windows平台会自动用 ‘\r\n’ 作为行结束符。可以使用os模块中的linesep变量来获得当前OS对应的行结束符。

最后一项是 ‘+’ 文件模式,表示读写模式,必须与其他文件模式一起使用,如 ‘r+’'w+’‘a+’。这三个组合文件模式都可以对文件进行读写操作,它们之间的区别如下。

  • r+ : 文件可读写,如果文件不存在,会抛出异常; 如果文件存在,会从当前位置开始写入新内容,通过seek 函数可以改变当前的位置,也就是文件指针。
  • w+ : 文件可读写,如果文件不存在,会创建一个新文件; 如果文件存在,会清空整个文件,并写入新内容。
  • a+ : 文件可读写,如果文件不存在,会创建一个新文件; 如果文件存在,会将要写入的内容添加到原文件的最后,也就是说,使用 ‘a+’ 模式打开文件,文件指针会直接跳到文件的尾部,如果要使用read方法读取文件内容,需要使用seek方法改变文件指针,如果调用seek(0)会直接将文件指针移到文件开始的位置。

13.2 操作文件的基本方法

13.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')
# 以追加的方式写入文件,每次写都另起一行
print(f.write('I love '))
print(f.write('python'))
f.close()

# 以读模式打开文件
f = open('./files/test1.txt', 'r')
# 读取7个字符
print(f.read(7))
# 继续再读6个字符
print(f.read(6))
f.close()


try:
    # 如果文件不存在,则抛出异常
    f = open('./files/test2.txt','r+')
except Exception as e:
    print(e)
# 用追加可读写模式打开文件
f = open('./files/test2.txt', 'a+')
print(f.write('hello'))
f.close()

f = open('./files/test2.txt', 'a+')
# 由于文件指针已经在文件末尾,所以什么内容都读不出来
print(f.read())
# 将指针设置到文件开始的位置
f.seek(0)
print(f.read())
f.close()

try:
    # 用写入可读写模式打开文件,该文件内容会被清空
    f = open('./files/test2.txt', 'w+')
    # 没有任何内容
    print(f.read())
    f.write('How are you?')
    f.seek(0)
    # 读取写入的内容
    print(f.read())
finally:
    f.close()

13.2.2 管道输出

在Linux、UNIX、Mac OS X等系统的Shell 中,可以在一个命令后面写另外一个命令,前一个命令的执行结果将作为后一个命令的输入数据,这种命令书写方式被称为管道,多个命令之间要使用符号分隔。

在 Python程序中,可以通过标准输入来读取从管道传进来的数据,所以 python命令也可以使用在管道命令中。

test.py 脚本

import sys
import os
import re
# 从标准输入读取全部数据
text = sys.stdin.read()
# 将字符串形式的文件和目录列表按行拆分,然后保存到列表中
files = text.split(os.linesep)
for file in files:
	# 匹配每一个文件名和目录名,只要包含“readme”,就符合条件
	result = re.match('.*readme.*',file)
	if result != None:
# 输出满足条件的文件名或目录名
		print(file)
# 在shell命令行就可以结合管道符使用
ls -al ~ | python test.py | sort

13.2.3 读行和写行

读写一整行是纯文本文件最常用的操作,尽管可以使用read和 write方法加上行结束符来读写文件中的整行,但比较麻烦。因此,如果要读写一行或多行文本,建议使用readline方法、readlines 方法和writelines方法。注意,并没有writeline方法,写一行文本需要直接使用write方法。

readline方法用于从文件指针当前位置读取一整行文本,也就是说,遇到行结束符停止读取文本,但读取的内容包括了行结束符。readlines方法从文件指针当前的位置读取后面所有的数据,并将这些数据按行结束符分隔后,放到列表中返回。writelines方法需要通过参数指定一个字符串类型的列表,该方法会将列表中的每一个元素值作为单独的一行写入文件。

import os
# 以读写模式打开文件urls.txt
f = open('./files/urls.txt','r+')
# 保存当前读上来的文本
url = ''
while True:
    # 从urls.txt读取一行文本
    url = f.readline()
    # 将最后的行结束符去掉
    url = url.rstrip()
    if url == '':
        # 读出来的是空串,结束循环
        break;
    else:
        # 输出读上来的行文本
        print(url)
print('-----------')
# 将文件指针重新设置为0
f.seek(0)
# 读取文件所有行
print(f.readlines())

# 向文件追加一个新行
f.write('https://jiketiku.com' + os.linesep)
f.close()

# 以追加的读写模式打开文件
f = open('./files/urls.txt','a+')
# 定义一个要写入文件的列表
urlList = ['https://geekori.com' + os.linesep, 'https://www.google.com' + os.linesep]
# 将列表内容写入文件
f.writelines(urlList)
f.close()

13.3 使用 FileInput 对象读取文件

如果需要读取一个非常大的文件,使用readlines 函数会占用太多内存,因为该函数会一次性将文件所有的内容都读到列表中,列表中的数据都需要放到内存中,所以非常占内存。为了解决这个问题,可以使用for循环和 readline方法逐行读取,也可以使用fileinput模块中的 input函数读取指定的文件.

input方法返回一个FileInput对象,通过FileInput对象的相应方法可以对指定文件进行读取,FileInput对象使用的缓存机制,并不会一次性读取文件的所有内容,所以比 readlines 函数更节省内存资源。

import fileinput
# 使用input方法打开urls.txt文件
fileobj = fileinput.input('./files/urls.txt')
# 输出fileobj的类型
print(type(fileobj))

# 必须在第1行读取后再调用,否则返回None
print(fileobj.readline().rstrip())
# 循环输出文件的其他行
for line in fileobj:    
    line = line.rstrip()
    # 行不为空就循环读,否则输出文件名
    if line != '':
        print(fileobj.lineno(),':',line)
    else:
        print(fileobj.filename())  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值