python文件操作

BitTigerio 2018-01-28

首先,我们需要知道一个概念:应用程序是不能直接对电脑硬件进行操作的

在操作系统中,操作系统对外提供了文件系统,硬盘上的文件都由文件系统进行资源管理,

读写硬盘是一种硬件操作,所以我们要想进行文件操作,就必须通过文件系统这个接口来进行文件操作

因此

我们要想进行文件读写等操作,就必须先向操作系统发起系统调用,
由操作系统的内核来进行文件的读写操作,
操作系统把执行结果返回给应用程序,
最后则应用程序把执行结果呈现在用户面前

python提供了一个进行文件读写操作的系统调用方法:open()

open()是python内置函数,我们可以通过调用open()函数来向操作系统发起系统调用,进行文件的读写操作

open()函数的用法

新建一个open_func.py文件,再新建一个file1.txt文件

file1.txt文件内容为:

离离原上草,
一岁一枯荣。
野火烧不尽,
春风吹又生。

先在open_func.py文件中打开file1.txt

>>> f=open("file1.txt")     # 没有指定file1.txt文件的绝对路径,所以这里用的是相对路径
                            # 第二个参数为读取文件的模式,不写默认为"r",即读取模式
                            # 把打开文件的句柄赋值给一个变量f
>>> print(f)
<_io.TextIOWrapper name='file1.txt' mode='r' encoding='UTF-8'>
>>> f.read()                # f.read()会读取指定文件的指定长度字符的内容,如果没有指定读取长度,则读取所有内容
'离离原上草,\n一岁一枯荣。\n野火烧不尽,\n春风吹又生。\n'
>>> f.read()                # 再次调用f.read()方法,其打印结果为空,也说明上一次f.read()读取指定文件的所有内容
''
>>> f.close()               # 关闭文件

需要注意的点:

  • 打开一个文件操作完成后一定要关闭这个文件,否则被打开的文件会一直存在于系统内存中,占用系统资源

指定读取长度的方法:f.read()

[root@bogon ~]# cat file2.txt       # 在系统命令提示符下查看文件file2.txt的内容
python
linux
mysql

>>> f=open("file2.txt")             # 以默认方式打开一个不存在的文件file2.txt,会抛出异常
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
FileNotFoundError: [Errno 2] No such file or directory: 'file2.txt'

在python解释器中进行操作

>>> f=open("file2.txt","r")         # 以读模式打开文件
>>> f.read(2)                       # 读取两个字符
'py'
>>> f.read(5)                       # 再向后读取5个字符
'thon\n'
>>> f.read(5)                       # 再次继续读取5个字符
'linux'
>>> f.close()                       # 关闭文件

一次读取一行内容的方法:f.readline()

>>> f=open("file1.txt")     # 再次打开file1.txt文件
>>> f.readline()            # f.readline()方法执行一次读取文件的一行内容
'离离原上草,\n'
>>> f.readline()            # 再次执行f.readline()方法,会接着光标在文件中的内容再次读取文件的一行内容
'一岁一枯荣。\n'
>>> print(f.readline(),end="")      # 这次使用print()方法打印f.readline()方法读取的一行内容,并指定文件结尾
野火烧不尽,
>>> print(f.readline(),end="")
春风吹又生。
>>> f.readline()            # 文件已经被读取完了,再次调用f.readline()方法读取文件内容会返回空
''
>>> f.close()               # 因为文件已经被读取完,光标已经被移动到文件的末尾了,所以关闭文件

读取整个文件内容生成列表的方法:f.readlines()

>>> f=open("file1.txt")     # 打开文件
>>> f.readlines()           # f.readlines()会一次性读取文件的所有内容,并把每一行做为一个元素放入一个列表中
['离离原上草,\n', '一岁一枯荣。\n', '野火烧不尽,\n', '春风吹又生。\n']
>>> f.write("aaa")          # 向文件中写入一行"aaa",因为是以读的方式打开文件,所以调用f.write()方法向文件中写入一行是会提示错误:无法写入
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
io.UnsupportedOperation: not writable
>>> f.close()

现在再以"w"的方式打开文件

>>> f=open("file1.txt","w")     # 以"w"的方式打开文件
>>> f.close()                   # 关闭文件
重新打开一个命令窗口,查看file1.txt文件的内容

在前面的例子里,file1.txt文件里是有内容的,但是在这里查看文件内容却是空了

[root@bogon ~]# cat file1.txt       # 可以看到文件中没有任何内容
[root@bogon ~]# ll file1.txt        # 文件大小变为0了
-rw-r--r-- 1 root root 0 Jan 27 22:46 file1.txt

在上面的例子里,我们可以看到,以"w"的方式打开文件时,会清除指定文件原有的内容

实际上,在python中,以"r"方式打开文件时,如果被打开的文件不存在时,是会抛出异常的
而以"w"模式打开文件时,如果文件不存在则新建这个文件,如果文件已经存在,则清空这个文件的原有内容

再看下一个例子

>>> f=open("file1.txt","w")         # 以"w"模式打开file1.txt
>>> f.write("hello world")          # 向文件中写入一行内容
11
>>> f.write("hello python")         # 向文件中再次写入一行内容
12
>>> f.close()                       # 关闭文件

在系统命令行中查看file1.txt文件的内容及大小

[root@bogon ~]# cat file1.txt       # 查看文件内容
hello worldhello python[root@bogon ~]# ll file1.txt
-rw-r--r-- 1 root root 23 Jan 27 22:59 file1.txt

查看文件内容可以看到文件中没有换行符,所以在向文件中写入内容时,需要我们自己在末尾处添加换行符

>>> f=open("file1.txt","w")         # 以"w"模式打开file1.txt
>>> f.write("hello python\n")       # 向文件中添加一行,在行尾添加换行符
13      
>>> f.write("hello world\n")        # 再次向文件中添加一行,在行尾也添加换行衔
12
>>> f.close()                       # 关闭文件

再次在系统命令提示符中查看文件内容及大小

[root@bogon ~]# cat file1.txt       # 查看文件内容,可以看到现在已经可以正常显示了
hello python    
hello world
[root@bogon ~]# ll file1.txt        # 查看文件大小
-rw-r--r-- 1 root root 25 Jan 27 23:03 file1.txt

在对文件进行读操作时,f.readlines会一次性读取文件的所有内容,并把每一行做为一个元素添加到列表中
在对文件进行写操作时,也有一个f.writelines方法.

把一个以字符串为元素的列表写入到文件中的方法:f.writelines()

f.writelines()方法可以把一个列表的元素做为行写入到文件中

需要注意的是:列表中的元素必须是字符串类型

>>> f=open("file1.txt","w")
>>> f.writelines(["python\n","linux\n","mysql\n"])      # 调用f.writelines()方法把一个列表写入到一个文件中
>>> f.close()

在系统命令提示符窗口中查看文件内容及大小

[root@bogon ~]# cat file1.txt       # 查看文件内容
python
linux
mysql
[root@bogon ~]# ll file1.txt
-rw-r--r-- 1 root root 19 Jan 27 23:09 file1.txt

可以看到字符串元素的列表已经被写入到文件中去了。

以"a"模式打开文件并进行操作

以"a"模式打开文件时,如果指定文件不存在,则创建指定文件
如果指定文件已经存在,则把光标移动到文件末尾,在文件最后一行进行添加内容操作

>>> f=open("file1.txt","a")     # 以"a"模式打开文件
>>> f.write("nginx\n")          # 向文件末尾追加一行内容
6
>>> f.write("javascript\n")     # 向文件末尾再次追加一行内容
11
>>> f.close()                   # 关闭文件

在系统命令提示符窗口中查看文件内容及大小

[root@bogon ~]# cat file1.txt   # 可以看到文件file1.txt的末尾已经添加了两行内容
python
linux
mysql
nginx
javascript
[root@bogon ~]# ll file1.txt    # 文件大小发生改变
-rw-r--r-- 1 root root 36 Jan 27 23:16 file1.txt

注意点:

在向文件中添加内容时,实际上是在内存中向文件添加内容的,只有等到文件被关闭的时候,解释器才会把内存中被修改的文件内容同步到文件中,在这个期间是有风险的,比如在文件未被保存到硬盘上之前,主机突然断电,那么这个文件的内容就有可以被损坏

这时可以使用f.flush()方法把内存中被修改的文件内容强行保存到硬盘中

手动把内存中的文件保存到硬盘上的方法:f.flush()

>>> f=open("file1.txt","a")         # 以追加模式打开文件
>>> f.write("mongodb\n")            # 向文件中添加一行内容
8
>>> f.write("openstack\n")          # 再次向文件中添加一行内容
10
>>> f.flush()                       # 调用f.flush()方法,把内存中的文件内容保存到硬盘中

在系统命令提示符窗口中查看文件内容及大小

[root@bogon ~]# cat file1.txt       # 在前面,并没有关闭文件,在这里还是可以看到添加后的文件内容
python
linux
mysql
nginx
javascript
mongodb
openstack
[root@bogon ~]# ll file1.txt        # 文件大小发生改变
-rw-r--r-- 1 root root 54 Jan 28 10:57 file1.txt

f.closed查看文件是否关闭,返回一个布尔值

这个例子接着上面的例子进行操作

>>> f.closed        # 在上面的例子里,调用f.flush()方法把内存中的文件内容保存到硬盘上,并没有关闭文件,查看文件是否关闭,返回False,说明文件没有关闭
False
>>> f.close()       # 关闭文件
>>> f.closed        # 再次查看文件是否关闭,返回True说明文件已经关闭了
True

把光标移动到文件指定位置的方法:f.seek(offset[,whence])

参数说明:

第一个参数为移动的字节数,第二个参数表示从哪个位置开始移动,
0表示以文件开始为参照点
1表示以当前位置为参数点
2表示以文件末尾位置为参照点

例子:

>>> f=open("file1.txt","rb")        # 在这里必须以"b"模式打开文件,否则会抛出异常
>>> f.seek(5)                       # 当前光标在文件首部,把光标从文件首部向后移动5个字节
5
>>> f.seek(5,1)                     # 再以光标当前所有位置为参照,向后移动五个字节
10
>>> f.tell()                        # 查看当前光标所在位置
10
>>> f.seek(3,1)                     # 以光标当前所在位置为参照,向后移动3个字节
13
>>> f.tell()                        # 查看当前光标所有位置
13
>>> f.seek(-2,2)                    # 把光标移动到文件末尾,然后再向前移动2个字节
52
>>> f.read()                        # 读取光标所在处到文件末尾的所有内容
b'k\n'
>>> f.tell()                        # 查看光标所在位置
54
>>> f.close()

查看当前光标所在位置的方法:f.tell()

f.tell()方法的位置为字节,返回值为数字

例子:

>>> f=open("file1.txt","r")
>>> f.read()
'python\nlinux\nmysql\nnginx\njavascript\nmongodb\nopenstack\n'
>>> f.seek(10)
10
>>> f.tell()
10
>>> f.read()
'ux\nmysql\nnginx\njavascript\nmongodb\nopenstack\n'
>>> f.tell()
54

以光标所在位置为参照,截取指定长度的内容,其余内容被删除:f.truncate()

例子:

>>> f=open("file2.txt","w")         # 以写模式打开文件
>>> f.write("1111111\n")            # 向文件中写入一行内容
8
>>> f.write("2222222\n")            # 向文件中写入第二行内容
8
>>> f.write("3333333\n")            # 向文件中写入第三行内容
8
>>> f.truncate(5)                   # 从文件开始位置向后截取5个字节的长度的内容
5
>>> f.close()

在系统命令提示符下查看文件内容

[root@bogon ~]# cat file2.txt
11111[root@bogon ~]#

其余的用法

f.name              # 获取被打开文件的文件名
f.encoding          # 获取文件的被打开的编码方式
f.readable()        # 判断文件当前是否可读
f.writable()        # 判断文件当前是否可写

例子:

>>> f=open("file1.txt","r")         # 以读模式打开文件file1.txt
>>> f.name                          # 查看文件名
'file1.txt'     
>>> f.encoding                      # 查看文件以哪种编码方式被打开
'UTF-8'
>>> f.readable()                    # 以读模式打开此文件,所以判断文件是否可读,返回值为True
True
>>> f.writable()                    # 以读模式打开此文件,所以判断文件是否可写,返回值为False
False   
>>> f.close()                       # 关闭文件
>>> f=open("file2.txt","w")         # 以写模式打开文件file2.txt
>>> f.name
'file2.txt'
>>> f.encoding
'UTF-8'
>>> f.readable()                    # 以写模式打开文件,所以在这里判断文件是否可读时,返回False
False
>>> f.writable()                    # 以写模式打开文件,判断文件可写返回值为True
True
>>> f.close()

在python中除了上面说的三种打开文件的办法外,还有另外一种打开文件的方法,那就是以二进制模式打开文件,即"rb","wb","ab"

现有另一个文件file2.txt,内容为

离离原上草,
一岁一枯荣。
野火烧不尽,
春风吹又生。

"rb"模式打开文件file2.txt,查看读取到的内容

>>> f=open("file2.txt","rb")    # 以读模式打开文件file2.txt
>>> f.read()                    # 查看文件内容时,可以看到是bytes格式的
b'\xe7\xa6\xbb\xe7\xa6\xbb\xe5\x8e\x9f\xe4\xb8\x8a\xe8\x8d\x89\xef\xbc\x8c\n\xe4\xb8\x80\xe5\xb2\x81\xe4\xb8\x80\xe6\x9e\xaf\xe8\x8d\xa3\xe3\x80\x82\n\xe9\x87\x8e\xe7\x81\xab\xe7\x83\xa7\xe4\xb8\x8d\xe5\xb0\xbd\xef\xbc\x8c\n\xe6\x98\xa5\xe9\xa3\x8e\xe5\x90\xb9\xe5\x8f\x88\xe7\x94\x9f\xe3\x80\x82\n'

>>> f=open("file2.txt","rb")
>>> f.read().decode("utf8")     # 因为写入时是以"utf8"编码格式写入的,所以在这里要解码成"utf8"格式的
'离离原上草,\n一岁一枯荣。\n野火烧不尽,\n春风吹又生。\n'

>>> f=open("file3.txt","wb")    # 以写模式打开文件file3.txt
>>> f.write("python")           # 此时直接向f对象中写入内容会抛出异常:写入的内容需要是bytes对象,不能是字符串格式的
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: a bytes-like object is required, not 'str'
>>> f.write("python\n".encode("utf8"))      # 编码成'utf8'格式,再写入
7
>>> f.write("你好呀\n".encode("utf8"))
10
>>> f.close()

在系统命令提示符下查看文件大小及内容

[root@bogon ~]# cat file3.txt
python
你好呀
[root@bogon ~]# ll file3.txt
-rw-r--r-- 1 root root 17 Jan 28 16:41 file3.txt

以"b"模式打开文件的好处:

1.读取文件的时候就是二进制格式的,不容易产生乱码
2.处理非文本类型的文件时,写入文件的时候就需要以二制格式写入,否则会抛出异常

例子:

用python的二进制方法把一个张图片aa.jpg复制一份bb.jpg

read_file=open('aa.jpg','rb')
write_file=open("bb.jpg","wb")
write_file.write(read_file.read())
[root@bogon ~]# ll *.jpg
-rw-r--r-- 1 root root 95406 Jan 19 08:38 aa.jpg
-rw-r--r-- 1 root root 95406 Jan 28 17:15 bb.jpg

总结:

打开文件时,需要指定文件路径和打开方式。打开文件后,即可获取指定文件的文件句柄,然后通过操作文件句柄来操作指定文件
    
    打开文件的模式有:
    r       只读模式,打开文件默认模式,文件必须存在,不存在则抛出异常
    w       只写模式,文件不存在则创建,存在则清空原有内容
    a       追加模式,可以读取文件,文件不存在则创建,存在则向文件追加内容

“+”表示可以同时读写某个文件

r+      读写(可读可写)
w+      写读(可读可写)
a+      写读(可读可写)

"b"表示以字节的方式操作

rb
wb
ab

以b方式打开文件时,读取到的内容是字节类型,写入时也需要提供字节类型,不能指定编码

小demo:

用python方法,替换文件中的内容

查看初始文件内容

[root@bogon ~]# cat test.txt 
aaaapythonaaaapythonaa
bbbblinuxbbblinuxbbb
cccmysqlcccmysqlccc
dddnginxdddnginxddd

现在想打test.txt文件中所有的nginx换成httpd

脚本如下:

import os


read_f = open("test.txt", "r")
write_f = open(".text.txt.swap", "w")

for line in read_f:
    if 'nginx' in line:
        line = line.replace("nginx", "httpd")
    write_f.write(line)

read_f.close()
write_f.close()

os.remove("test.txt")
os.rename(".text.txt.swap", "test.txt")

运行这个python脚本,然后查看test.txt的内容

[root@localhost ~]# cat test.txt 
aaaapythonaaaapythonaa
bbbblinuxbbblinuxbbb
cccmysqlcccmysqlccc
dddhttpddddhttpdddd

会发现文件test.txt的内容已经被修改了

with上下文管理

使用open打开文件时,很容易会忘记关闭被打开的文件,这要一来被打开的文件一直运行在内存中,无形中造成了系统资源的浪费

这时可以使用with上下文管理来进行文件操作,以解决因为忘记关闭文件而造成的系统资源的浪费

使用with重构上面的内容替换的例子

import os

with open("a.txt","r") as read_f,open(".a.txt.swap","w") as write_f:
    for line in read_f:
        if "nginx" in line:
            line=line.replace("nginx","httpd")
        write_f.write(line)

os.remove("a.txt")
os.rename(".a.txt.swap","a.txt")

也可以完成同样的功能,而且不用手动关闭被打开的文件

相关推荐