Python 第九章 文件操作
1.使用os.path操作目录
import os
import time
# 获取绝对路径
print(os.path.abspath("abc.txt")) # G:\publish\codes\12\12.2\abc.txt
# 获取共同前缀
print(os.path.commonprefix(['/usr/lib', '/usr/local/lib'])) # /usr/l
# 获取共同路径
print(os.path.commonpath(['/usr/lib', '/usr/local/lib'])) # \usr
# 获取目录
print(os.path.dirname('abc/xyz/README.txt')) #abc/xyz
# 判断指定目录是否存在
print(os.path.exists('abc/xyz/README.txt')) # False
# 获取最近一次访问时间
print(time.ctime(os.path.getatime('os.path_test.py')))
# 获取最后一次修改时间
print(time.ctime(os.path.getmtime('os.path_test.py')))
# 获取创建时间
print(time.ctime(os.path.getctime('os.path_test.py')))
# 获取文件大小
print(os.path.getsize('os.path_test.py'))
# 判断是否为文件
print(os.path.isfile('os.path_test.py')) # True
# 判断是否为目录
print(os.path.isdir('os.path_test.py')) # False
# 判断是否为同一个文件
print(os.path.samefile('os.path_test.py', './os.path_test.py')) # True
2.打开文件
open()函数默认打开文件的模式是r,只读。
在使用open函数时,如果其第三个参数是0或False,那么该函数打开的文件就是不带缓冲的,是1或True就带,就有更好的性能。如果是大于1的整数,就是知道缓冲区大小,是负数就代表默认的缓冲区大小。
打开文件之后就可调用文件对象的属性和方法了。文件对象支持如下常见的属性:
- file.closed:该属性返回文件是否已经关闭
- file.mode:该属性返回被打开文件的访问模式
- file.name:返回文件的名称
# 以默认方式打开文件
f = open('open_test.py')
# 访问文件的编码方式
print(f.encoding) # cp936
# 访问文件的访问模式
print(f.mode) # r
# 访问文件是否已经关闭
print(f.closed) # False
# 访问文件对象打开的文件名
print(f.name) # open_test.py
文件打开模式:
- r:只读模式。
- w:写模式。
- a:追加模式。
- +:读写模式,可与其他模式结合使用。比如r+,w+都是读写模式。
- b:二进制模式,可与其他模式结合使用。
w代表写模式,w+代表读写模式,但实际上他们差别不大,当这两种模式打开指定文件时,open函数都会立即清空文件内容,实际上都无法读取文件内容。
3.读取文件
3.1按字节或字符读取
文件对象提供read函数来按字节或字符读取文件内容,如果使用了b模式就按字节读,可以传入一个整数作为参数,用于指定最多读取多少个字节或字符。
f = open('基础.py','r',True,encoding='utf-8')
while True:
# 每次读取一个字符
ch = f.read(1)
# 如果没有读到数据就跳出循环
if not ch:break
print(ch,end='')
f.close()
上面程序采用循环一次读取每一个字符,每读到一个字符,程序就输出该字符。
如果在调用read函数时不传入参数,默认读取全部文件内容。
如果要读取的文件所使用的字符集和当前操作系统的字符集不匹配,有两种解决方法:
- 使用二进制模式读取,然后用bytes的decode()方法恢复成字符串。
- 利用open函数的encoding参数指定字符集。
# 指定使用二进制方式读取文件内容
f = open("read_test3.py", 'rb', True) # rb模式采用二进制读
# 直接读取全部文件,并调用bytes对象的decode将字节内容恢复成字符串
print(f.read().decode('utf-8'))
f.close()
3.2按行读取
如果程序要读取行,通常只能用文本方式来读取,只有文本文件才有行的概念,二进制文件没有。
- readline([n]):读取一行内容,如果指定n,就只能读取此行内的n个字符。
- readlines():一下子读取文件所有行。
3.3使用fileinput读取多个输入流
fileinput模块可以把多个输入流合并在一起。
- fileinput.input(files=None,inplace=False,backup='',bufsize=0,mode='r',openhook=None):files参数用于指定多个文件输入流。该函数返回一个Fileinput对象。
- fileinput.filename():返回文件名
- fileinput.fileno():返回当前文件的文件描述符。
- fileinput.lineno():当前读取的行号。
- 等等
这个模块不能指定字符集。
import fileinput
# 一次读取多个文件
for line in fileinput.input(files=('info.txt', 'test.txt')):
# 输出文件名,当前行在当前文件中的行号
print(fileinput.filename(), fileinput.filelineno(), line, end='')
# 关闭文件流
fileinput.close()
3.4文件迭代器
文件对象本身就是可遍历的,所以可以用for in循环来遍历文件内容
# 指定使用utf-8字符集读取文件内容
f = open("for_file.py", 'r', True, 'utf-8')
# 使用for-in循环遍历文件对象
for line in f:
print(line, end='')
f.close()
# 将文件对象转换为list列表
print(list(open("for_file.py", 'r', True, 'utf-8')))
此外,sys.stdin也是一个类文件对象,因此程序可以用for in循环遍历,这意味着程序可以通过forin循环获取用户的键盘输入。
import sys
# 使用for-in循环遍历标准输入
for line in sys.stdin:
print('用户输入:', line, end='')
获取用户键盘输入,用户每输入一行就会显示这一行。
3.5管道输入
3.6使用with语句
可以自动关闭文件
# 使用with语句打开文件,该语句会负责关闭文件
with open("readlines_test.py", 'r', True, 'utf-8') as f:
for line in f:
print(line, end='')
3.7使用linecache随机读取指定行
随机读取使用了utf-8字符集的指定行
import linecache
import random
# 读取random模块的源文件的第3行
print(linecache.getline(random.__file__, 3))
# 读取本程序的第3行
print(linecache.getline('linecache_test.py', 3))
# 读取普通文件的第2行
print(linecache.getline('utf_text.txt', 2))
4.写文件
如果以r+、w、w+、a、a+模式打开文件,则都可以写入。当以r+、w、w+打开文件时,文件指针位于文件开头处;当以a、a+模式打开文件时,文件指针位于文件结尾。当以w、w+打开文件时,程序会立即清空文件的内容。
4.1文件指针:
用于标明文件读写的位置。
文件对象提供以下方法操作文件指针:
seek(offset[,whence]):该方法把文件指针移动到指定位置。当whence为0时(这是默认值),表面从文件开头开始计算,比如将offset设为3,就是将文件指针移动到第3处;当whence为1时,表明从指针当前位置开始计算,比如文件指针当前在第5处,将offset设为3,就是将文件指针移动到第8处;当whence为2时,表面从文件结尾开始计算,比如将offset设为-3,表面将指针移动到文件结尾倒数第3处。
tell():判断文件指针的位置。
当程序使用文件对象读写数据时,文件指针会自动向后移动:读写了多少个数据,就向后移动多少个位置。
f = open('filept_test.py', 'rb')
# 判断文件指针的位置
print(f.tell()) # 0
# 将文件指针移动到3处
f.seek(3)
print(f.tell()) # 3
# 读取一个字节,文件指针自动后移1个数据
print(f.read(1)) # o
print(f.tell()) # 4
# 将文件指针移动到5处
f.seek(5)
print(f.tell()) # 5
# 将文件指针向后移动5个数据
f.seek(5, 1)
print(f.tell()) # 10
# 将文件指针移动到倒数第10处
f.seek(-10, 2)
print(f.tell())
print(f.read(1)) # d
4.2输出内容
文件对象提供的写文件的方法主要有两个:
- write(str或bytes):输出单个字符串或字节串。只有以二进制
- writelines(可迭代对象):输出多个字符串或多个字节串
import os
f = open('x.txt', 'w+')
# os.linesep代表当前操作系统上的换行符
f.write('我爱Python' + os.linesep)
f.writelines(('土门壁甚坚,'+ os.linesep,
'杏园度亦难。'+ os.linesep,
'势异邺城下,'+ os.linesep,
'纵死时犹宽。'+ os.linesep))
当采用上面方法输出文件时,程序会使用当前操作系统默认的字符集。如果需要使用指定的字符集来输出文件,则可以用二进制形式----程序先将所输出的字符串转换成指定字符集对应的二进制数据(字节串),然后输出二进制数据。
import os
f = open('y.txt', 'wb+')
# os.linesep代表当前操作系统上的换行符
f.write(('我爱Python' + os.linesep).encode('utf-8'))
f.writelines((('土门壁甚坚,'+ os.linesep).encode('utf-8'),
('杏园度亦难。'+ os.linesep).encode('utf-8'),
('势异邺城下,'+ os.linesep).encode('utf-8'),
('纵死时犹宽。'+ os.linesep).encode('utf-8')))
以wb+模式打开文件,程序会以二进制形式输出文件,此时程序输出的必须是字节串,不能是字符串。因此程序调用encode方法将字符串转换成字节串,转换时指定使用utf-8字符集。
以w+、wb+模式打开文件会导致文件内容被清空,因此无论程序运行多少次,其输出的文件内容都只保留最近一次的输出数据。要想继续写要使用追加模式:
import os
f = open('z.txt', 'a+')
# os.linesep代表当前操作系统上的换行符
f.write('我爱Python' + os.linesep)
f.writelines(('土门壁甚坚,'+ os.linesep,
'杏园度亦难。'+ os.linesep,
'势异邺城下,'+ os.linesep,
'纵死时犹宽。'+ os.linesep))