【Python】文件

一. 什么是文件

数据因为表现形式的不同会被划分成各种各样的文件:

  • 电影(.mp4)
  • 歌曲(.mp3)
  • 图片(.jpg)
  • 文本(.txt)
  • 表格(.xlsx)

我们知道冯诺依曼体系结构包括:输入输出设备、存储器、运算器和处理器。其中存储器的存储体系又分为内存和硬盘:

  • 内存:变量就是存储在内存中
  • 硬盘:文件就是存储在硬盘中

对比内存和硬盘:

  1. 内存的空间更小,硬盘的空间更大
  2. 内存访问更快,硬盘访问更慢
  3. 内存成本更高,硬盘成本更低
  4. 内存的数据易丢失,硬盘的数据能持久化存储

我们电脑中C盘、D盘的内容都是硬盘上的内容,也都是文件:
在这里插入图片描述

二. 文件路径

文件夹也叫目录,它也属于文件。我们把一层层目录构成的字符串称为“文件的路径”,比如在我的电脑中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 个文件是什么呢?其实在每个程序启动的时候,都会默认打开三个文件:

  • 标准输入(stdin),代表键盘
  • 标准输出(stdout),代表显示器
  • 标准错误(stderr),代表显示器

少了的那三个文件就是它们,它三在程序启动之初就已经打开了。

五. 写文件

1. 清空写

使用write方法可以对文件内容进行写入:

f = open('C:/Users/86158/Downloads/Python/test.txt', 'w')
f.write('hello')
f.close()

编译运行后,观察 test.txt 文件,成功写入字符串 “hello”:
在这里插入图片描述

注意如果要写文件,打开文件时需要使用 ‘w’ 的方式,如果是 ‘r’ 方式打开,则会抛出异常:
在这里插入图片描述

2. 追加写

写方式打开文件,其实有两种情况,直接写方式打开和追加写方式打开:

  • ‘w’:对文件写入时,会清空原有文件的内容
  • ‘a’:不会清空原有文件的内容,写的内容会追加到原有文件内容的末尾
# 用追加的方式对 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')

抛出异常:
在这里插入图片描述

六. 读文件

1. 使用 read 方法读取

假设 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()


-------运行结果-------
床前

2. 使用 for 循环按行读取

使用 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()

-------运行结果-------
床前看月光 
疑是地上霜
举头望山月 
低头思故乡

3. 使用 readlines 方法读取整个文件的内容

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 方法,这时读取文件内容的效率不高。

七. 上下文管理器

1. 什么是上下文管理器?

通过上下文管理器方式去打开、操作文件,我们可以不去担心文件最终是否忘了关闭了,从而导致资源泄露。

不同高级语言有不同的防止资源泄露的管理方式:

  • Python:上下文管理器
  • C++:智能指针
  • Java:try with Resources
  • Golang:defer

2. 为什么要有上下文管理器?

有些情况防不胜防,因为一些代码逻辑的原因,我们不能保证文件最终真的被关闭了:

在这里插入图片描述

3. 怎么使用上下文管理器?

打开文件之后,是容易忘记关闭的。Python 提供了上下文管理器,来帮助程序员自动关闭文件。

语法如下:

with open('d:/test.txt', 'r', encoding='utf8') as f:
    # 这里进行文件的处理逻辑,比如
    lines = f.readlines()
    print(lines)

它有以下两个作用:

  • 使用 with 语句打开文件
  • 当 with 内部的代码块执行完毕后, 就会自动调用关闭方法

示例:
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值