数据因为表现形式的不同会被划分成各种各样的文件:
我们知道冯诺依曼体系结构包括:输入输出设备、存储器、运算器和处理器。其中存储器的存储体系又分为内存和硬盘:
对比内存和硬盘:
文件夹也叫目录,它也属于文件。我们把一层层目录构成的字符串称为“文件的路径”,比如在我的电脑中QQ可执行程序的路径就是:C:\Program Files (x86)\Tencent\QQ\Bin
文件路径可以视为是文件在硬盘上的身份标识,每个文件对应的路径都是唯一的。知道了文件路径,就可以知道这个文件在硬盘上的详细位置;也就可以进一步的知道这个文件里面都有些什么。
补充说明
目录名之间,使用反斜杠 \ 来分隔,其实使用斜杆 / 也可以。前者 Windows 用的更多,在其他系统中更多的是使用斜杆来分隔,因为反斜杠在字符串中有特殊的含义,它可以表示转意。
创建一个文档文件 test.txt 用来测试:
在 Python 中打开文件使用open
函数:
f = open('C:/Users/86158/Downloads/Python/test.txt', 'r')
print(f)
print(type(f))
-------运行结果-------
# 包含文件的路径、打开方式、编码方式这三个信息
<_io.TextIOWrapper name='C:/Users/86158/Downloads/Python/test.txt' mode='r' encoding='cp936'>
# Python内部给文件对象起的名字
<class '_io.TextIOWrapper'>
open 函数解析
补充说明
1)被打开的文件必须存在于给出的路径下,不然会抛异常
2)文件对象是个句柄
open 的返回值是一个文件对象,如何理解?
文件对象就像一个遥控器,而文件就好像一台电视机。我们要操作电视机(开关、调台、调音量),可以直接去按电视机上的按键,但是这样太麻烦了,我们通常是躺在沙发上通过遥控器来操作;类比文件,我们可直接去硬盘上去对文件进行读写等操作,同样为了方便我们更多的是通过文件对象去完成这些操作。
使用close
方法关闭已经打开的文件:
f.close()
文件在打开、使用完了之后一定要关闭!
打开文件,其实是在申请一定的系统资源,不再使用文件的时候,资源就该及时释放;否则就可能造成文件资源泄露,进一步导致其他部分的代码无法顺利打开文件。
正是因为一个系统的资源是有限的,因此一个程序能打开的文件个数也是有上限的,通过下面代码测试
# 1、创建一个列表,用来存储文件对象
fList = []
# 2、无限地打开文件
count = 0
while True:
f = open('C:/Users/86158/Downloads/Python/test.txt', 'r')
fList.append(f)
count = count + 1
print(f'打开的无间隔数:{count}')
-------运行结果-------
...
打开的无间隔数:8187
打开的无间隔数:8188
打开的无间隔数:8189
OSError: [Errno 24] Too many open files: 'C:/Users/86158/Downloads/Python/test.txt'
发现 PyCharm 最终允许打开文件个数上限是:8189
我们可以通过一些设置项,来配置能打开的最大文件数目。但不论配置多少个,都不是无穷无尽的,还是需要我们做到及时关闭,释放资源。
此外,Python 中还有一个重要的机制:垃圾回收机制(GC),会自动的吧不使用的变量给进行释放。
这次我们还是无限地去打开文件,但不再把文件对象保存到列表中了:
count = 0
while True:
f = open('C:/Users/86158/Downloads/Python/test.txt', 'r')
count = count + 1
print(f'打开的无间隔数:{count}')
这次运行后发现不会抛异常了,之前抛异常是因为我们把打开的文件对象都存储到了列表中,然后操作系统判定我们之后可能还会使用这些文件对象,所以没有把它们回收;而这次我们只是单纯地打开了文件,而没有对它们进行任何操作,循环结束后操作系统就会把前面打开的文件对象自动回收。
总结:虽然 Python 给了我们一个后手,让我们一定程度地避免内存泄漏问题。但是也不能完全依赖自动回收机制,因为它不能做到绝对及时地释放,因此还是要尽量手动释放,做到万无一失。
补充:为什么 Python 把文件打开数目的上限设置为 8189 ?
因为:8189 + 3 = 8192 => 2^13
在计算机中所有的数据都是用二进制数字来表示的,因此计算机里的很多数字都是按照 2 的 n 次方这样的方式表示的;即在程序员眼中,1000 不是一个很整齐的数字,1024 => 2^10 这才是一个比较整齐的数字。
回归正题,那么 8189 少了的 3 个文件是什么呢?其实在每个程序启动的时候,都会默认打开三个文件:
少了的那三个文件就是它们,它三在程序启动之初就已经打开了。
使用write
方法可以对文件内容进行写入:
f = open('C:/Users/86158/Downloads/Python/test.txt', 'w')
f.write('hello')
f.close()
编译运行后,观察 test.txt 文件,成功写入字符串 “hello”:
注意如果要写文件,打开文件时需要使用 ‘w’ 的方式,如果是 ‘r’ 方式打开,则会抛出异常:
写方式打开文件,其实有两种情况,直接写方式打开和追加写方式打开:
# 用追加的方式对 test.txt 文件进行写入
f = open('C:/Users/86158/Downloads/Python/test.txt', 'a')
f.write('112233')
f.close()
观察 test.txt 文件的内容,发现新写入的内容追加到原内容的末尾:
这次用 ‘w’ 方式打开文件,然后进行写入:
f = open('C:/Users/86158/Downloads/Python/test.txt', 'w')
f.write('world')
f.close()
最后还要注意一点:如果文件对象已经被关闭,那么意味着系统中和该文件相关的内存资源已经被释放了,这时强行去写,也会抛出异常:
f = open('C:/Users/86158/Downloads/Python/test.txt', 'w')
f.close()
# error:对已经关闭的文件进行写操作
f.write('hello')
假设 test.txt 的文件内容如下:
接下来我们以 ‘r’ 方式打开文件,然后然后用 read 函数去读取文件内容;read 函数的参数是你要读取字符的个数,返回值是一个字符串:
f = open('C:/Users/86158/Downloads/Python/test.txt', 'r')
ret = f.read(2)
print(ret)
f.close()
原因是文件内容对中文的编码方式是 utf8;而我们打开文件时,对文件的操作的编码方式默认是 gbk,二者不匹配,所以导致读取文件内容失败:
此处我们使用的办法,是让代码按照 utf8 的方式来进行处理。相比于 gbk,utf8 是使用更广泛的编码方式。
f = open('C:/Users/86158/Downloads/Python/test.txt', 'r', encoding='utf8')
ret = f.read(2)
print(ret)
f.close()
-------运行结果-------
床前
使用 for 循环直接遍历文件对象,可以按行读到里面的内容:
f = open('C:/Users/86158/Downloads/Python/test.txt', 'r', encoding='utf8')
for line in f:
print(line)
f.close()
-------运行结果-------
床前看月光
疑是地上霜
举头望山月
低头思故乡
观察结果,发现每一句结束后,下面会多了一行,这是为什么呢?
之所以会多了一个空行,是因为本来读到的内容,每一行结束后末尾就带有一个 ‘\n’,此处再用 print 打印,又会自动加一个换行符。
我们可以给 print 再多设定个参数,修改 print 自动添加换行符的行为
重新编写代码,观察结果:
f = open('C:/Users/86158/Downloads/Python/test.txt', 'r', encoding='utf8')
for line in f:
print(line, end='')
f.close()
-------运行结果-------
床前看月光
疑是地上霜
举头望山月
低头思故乡
readlines 方法可以一次性读取整个文件的内容,不需要传参,它会按行读取文件的内容,然后把结果组织到一个列表当中作为返回值,返回给外界:
f = open('C:/Users/86158/Downloads/Python/test.txt', 'r', encoding='utf8')
ret = f.readlines()
print(ret)
f.close()
-------运行结果-------
['床前看月光 \n', '疑是地上霜\n', '举头望山月 \n', '低头思故乡']
PS:如果文件很大、内容很多的话,不建议使用 readlines 方法,这时读取文件内容的效率不高。
通过上下文管理器方式去打开、操作文件,我们可以不去担心文件最终是否忘了关闭了,从而导致资源泄露。
不同高级语言有不同的防止资源泄露的管理方式:
有些情况防不胜防,因为一些代码逻辑的原因,我们不能保证文件最终真的被关闭了:
打开文件之后,是容易忘记关闭的。Python 提供了上下文管理器,来帮助程序员自动关闭文件。
语法如下:
with open('d:/test.txt', 'r', encoding='utf8') as f:
# 这里进行文件的处理逻辑,比如
lines = f.readlines()
print(lines)
它有以下两个作用: