I/O (input output 输入输出)是所有程序都必需的能力,使用输入机制允许程序读取外部数据,使用输出机制,允许程序记录运行状态,将数据输出到磁盘等设备。
Python提供了非常丰富的I/O支持,既提供了pathlib和os.path来操作各种路径,也提供了全局的open()函数来打开文件,在打开文件后,程序既可以读取文件的内容,也可以向文件输出内容。
9.1 使用pathlib模块操作目录
pathlib模块提供了一组面向对象的类,这些类可代表各种操作系统上的路径,程序可通过这些类操作路径。
9.1.1 PurePath
PurePath: 代表并不访问实际文件系统的纯路径,只负责对路径字符串进行操作,至于该字符串是否对应实际的路径,并不关心。PurePath有两个子类,PurePosixPath(Unix风格的路径)、PureWindowsPath(Windows风格路径)
例子:
#!usr/bin/python3
from pathlib import *
pp = PurePath("haha.py")
print("type = ", type(pp)) #这行输出type = <class 'pathlib.PurePosixPath'>,因为mac也是unix 风格
print("pp = ", pp)
pp = PurePath("haha", "hehe", "heihei", "xixi")
print("pp2 = ", pp)
结果:
type = <class 'pathlib.PurePosixPath'>
pp = haha.py
pp2 = haha/hehe/heihei/xixi
如果创建PurePath时不传入参数,系统默认创建代表当前路径的PurePath,相当于传入点号(. 代表当前路径)
#!usr/bin/python3
from pathlib import *
pp = PurePath()
print("pp = ", pp)
结果:
pp = .
9.1.2 Path
Path是PurePath的子类,它除了支持PurePath的各种操作外,还会真正访问底层的文件系统,包括判断Path对应的路径是否存在,获取Path对应路径的各种属性,甚至可以对文件进行读写
Path同样提供了两个子类:PosixPath和WindowsPath,前者代表Unix风格的路径,后者代表Windows风格的路径
Path对象包含了大量的is_xxx()方法,用于判断Path对应的路径是否为xxx,Path包含一个exists()方法,用于判断该Path对应的目录是否存在
Path还包含一个很常用的iterdir()方法,该方法可以返回Path对应目录下的所有子目录和文件,此外,Path还包含一个glob()方法,用于获取Path对应目录及其子目录下匹配指定模式的所有文件,借助此方法,可以非常方便的查找指定文件
#!usr/bin/python3
from pathlib import *
p = Path(".")
#遍历当前路径下的文件
for x in p.iterdir():
print("x = ", x)
结果:将当前路径下的文件名都打印了出来
#!usr/bin/python3
from pathlib import *
#获取上一级目录
p = Path("../")
#获取上一级目录及其子目录下的.py文件
for x in p.glob("**/*.py"):
print("x = ", x)
9.1.3 使用Path读写文件
Path提供了read_bytes()和read_text()方法,分别用于读取该Path对应文件的字节数据(二进制数据)和文本数据,也提供了write_bytes()和write_text()方法来输出字节数据和文本数据,如下所示:
#!usr/bin/python3
from pathlib import *
path = Path("test1.txt")
result = path.write_text("hahahaha\nhehehe", encoding="GBK")
print("result = ", result)
content = path.read_text(encoding="GBK")
print("content = ", content)
b = path.read_bytes()
print("b = ", b)
结果:
result = 15
content = hahahaha
hehehe
b = b'hahahaha\nhehehe'
9.2 使用os.path操作目录
在os.path模块下提供了一些操作目录的方法,这些函数可以操作系统的目录本身,该模块提供了exists()函数用于判断该目录是否存在,也提供了其他函数,常用的有如下几个方法:
exists() : 判断文件/目录是否存在
getctime(): 获取该目录的创建时间
getmtime(): 获取该目录最后一次修改时间
getatime(): 获取该目录最后一次访问时间
getsize(): 获取指定文件的大小
isfile(): 判断是否是文件
isdir(): 判断是否是目录
#!usr/bin/python3
import os
file_path = "/Users/haha/Desktop/haha.txt"
print(os.path.exists(file_path))
print("创建时间 = ", os.path.getctime(file_path))
print("最后一次修改时间 = ", os.path.getmtime(file_path))
print("最后一次访问时间 = ", os.path.getatime(file_path))
print("isfile = ", os.path.isfile(file_path))
print("isdir = ", os.path.isdir(file_path))
结果:
True
创建时间 = 1652054926.2842386
最后一次修改时间 = 1652054926.274017
最后一次访问时间 = 1652054926.5356798
isfile = True
isdir = False
9.3 打开文件
有了以上内容的铺垫,接下来进入了本章的重点内容,即读写文件
python打开文件使用内置的open函数,f = open("/Users/haha/Desktop/haha.txt", "w") 其中第一个参数表示打开的文件路径,第二个参数w表示访问模式,python提供的访问模式有如下几个:
1. w表示写入(write)
2. r表示读(read)
3. a表示追加模式
4. r+ 和w+都表示读写模式
5. b表示二进制模式,可与其他模式混用,比如rb表示二进制只读模式,rb+表示二进制读写模式
需要注意的是当使用w和w+模式打开文件时,open()函数都会立即清空文件内容,实际上也就无法读取文件内容了,所以如果希望调用open()函数打开文件后,该文件中的内容能被保留下来,那么程序就不能使用w或w+模式了。
还有就是,如果程序使用r或r+模式打开文件,则要求被打开的文件本身是存在的,也就是说使用r或r+模式都不能创建文件,但如果使用w、w+、a、a+模式打开文件,则该文件可以是不存在的,open()函数会自动创建新文件
下图是根据不同场景可以选择的打开模式
9.1.1 打开文件的属性
文件打开后,会有一些属性,如获取文件名称、文件编码、访问文件的模式等,如下所示:
#!usr/bin/python3
f = open("/Users/haha/Desktop/haha.txt", "w")
print("文件编码: ", f.encoding)
print("文件访问模式: ", f.mode)
print("文件是否关闭: ", f.closed)
print("文件名称: ", f.name)
结果:
文件编码: UTF-8
文件访问模式: w
文件是否关闭: False
文件名称: /Users/haha/Desktop/haha.txt
9.2 文件读取
文件对象提供了read()方法来按字节或者字符串读取文件内容,到底是读取字节还是字符,取决于是否使用了b模式,如果使用了b模式,则每次读取一个字节,如果没有使用b模式,则每次读取一个字符。
9.2.1 普通读取
#!usr/bin/python3
f = open("/Users/haha/Desktop/haha.txt", "r")
str = f.read() #一次读取文件全部内容
print(str)
f.close()
结果:
haha10
hehe10
9.2.2 一次读取若干个字符
#!usr/bin/python3
f = open("/Users/haha/Desktop/haha.txt", "r")
while True:
ch = f.read(1)#参数是1表示一次读取1个字符,参数可以改成其他值
print(ch, end='')
if not ch:
break
f.close()
结果:
哈哈哈
hehehe
上面的程序采用循环的方式依次读取每一个字符,每读取到一个字符,程序就输出该字符,当程序读写完文件后,建议立即使用close()方法来关闭文件,这样可以避免资源泄露。
如果需要更安全的关闭文件,建议将关闭文件的close()方法调用在finally块中执行,如下所示:
9.2.3 使用字节的方式读取
除了二进制文件可以用rb方式读取,读取文本文件也可以,这个和Java中的字节流是一样的,下面看例子
#!usr/bin/python3
f = open("/Users/haha/Desktop/haha.txt", "rb")
a = f.read().decode("utf-8")
print("a = ", a)
结果:
a = 哈哈哈
hehehe
9.2.4 按行读取
如果程序要按行读取,只能用文本方式来读取,因为只有文本文件才有行的概念,二进制文件没有所谓行的概念
一次读取一行
#!usr/bin/python3
file = open("/Users/bytedance/Desktop/code/ai-ocr/test.txt", "r")
while True:
#遍历读取每一行
s = file.readline()
print("s = ", s)
if not s:
break
file.close()
一次读取所有行
#!usr/bin/python3
f = open("/Users/haha/Desktop/haha.txt", "r")
str = f.readlines()
print("str = ", str)
f.close()
结果:
str = ['haha10\n', 'hehe10\n']
#!usr/bin/python3
file = open("/Users/bytedance/Desktop/code/ai-ocr/test.txt", "r", True)
lines = file.readlines()
for line in lines:
print(line, end='')
9.2.5 迭代一个文件对象然后读取每行
#!usr/bin/python3
f = open("/Users/haha/Desktop/haha.txt", "r")
for line in f:
print(line)
f.close()
结果:
haha10
hehe10
9.2.6 with关键字
使用 with 关键字系统会自动调用 f.close() 方法, with 的作用等效于 try/finally 语句是一样的
#!usr/bin/python3
with open("/Users/bytedance/Desktop/haha.txt", 'r') as file:
str = file.read()
print("str = ", str)
结果:
str = haha10
hehe10
9.3 写文件
如图以r+、w、w+、a、a+模式打开文件,则都可以写入,需要说明的是,当以r+、w、w+模式打开文件时,文件指针位于文件开头处,当以a、a+模式打开文件时,文件指针位于文件结尾处。另外就是,如果以w或w+模式打开文件,程序会立即清空文件的内容。
9.3.1 使用write写文件
#!/usr/bin/python3
f = open("/Users/haha/Desktop/haha.txt", "w")
f.write("hahahaha\nheheheheh\n" )
# 关闭打开的文件
f.close()
结果:写到了文件中
#!usr/bin/python3
file = open("/Users/bytedance/Desktop/code/ai-ocr/test.txt", "wb+")
s = 'hahahah\nhehehe2'
file.write(s.encode("utf-8"))
writelines用法
#!usr/bin/python3
file = open("/Users/bytedance/Desktop/code/ai-ocr/test.txt", "w", True)
file.writelines("hahaha\nheheheh\nxixixi")
file.close()
9.3.2 使用print写文件
#!usr/bin/python3
f = open("/Users/haha/Desktop/haha.txt", "w")
print("hahahahahahahahahah", file=f)
print("hehehehehehehehheh", file=f)
结果:使用print写到了文件中,而不是打印到了控制台
9.3.3 使用追加模式
上面使用w写模式,会将文件内容清空后写入,原来的文件内容保留不了,如果需要在文件末尾追加,则需要用a或a+模式,如下所示:
#!usr/bin/python3
import os
f = open("/Users/bytedance/Desktop/haha.txt", "a+")
f.write("hahaha" + os.linesep)
f.close()
9.4 os模块的文件和目录函数
os模块下也提供了大量操作文件和目录的函数,下面介绍其用法
9.3.1 与目录相关的函数
os.getcwd() : 获取当前目录
os.chdir(path) : 改变当前目录
os.fchdir(fd) : 通过文件描述符改变当前目录
#!usr/bin/python3
import os
print(os.getcwd())
结果:
/Users/haha/source/builder/builder/handler
listdir() :返回指定路径下的文件和文件夹列表
#!/usr/bin/python3
import os
path = "/Users/haha/Desktop"
dirs = os.listdir(path)
for file in dirs:
print(file)
结果:
展示出path路径下的的所有其他文件或文件夹
mkdir(): 创建目录
makedirs(): 递归创建目录
#!usr/bin/python3
import os
path = "my_dir"
os.mkdir(path, 0o755)
path2 = "abc/xyz/my_dir"
os.makedirs(path2, 0o755)
结果:创建文件夹成功
rmdir(): 删除目录
removedirs(): 递归删除目录
#!usr/bin/python3
import os
path = "my_dir1"
path2 = "abc/xyz/my_dir1"
os.rmdir(path)
os.removedirs(path2)
结果:
删除成功