文件操作

1. 学前三问

1.1 什么是文件 ?

文件是操作系统提供给用户/应用程序操作硬盘的一种虚拟的概念/接口。

用户/应用程序
操作系统(文件)  操作系统会把对用户/应用程序文件功能的调用转成具体的硬盘操作
计算机硬件(硬盘)

1.2 为何要用文件

用户/应用程序可以通过文件将数据永久保存的硬盘中,即操作文件就是操作硬盘。

用户/应用程序直接操作的是文件,对文件进行的所有操作,都是在向操作系统发送系统调用,然后再由操作将其

转换成具体的硬盘操作。

1.3 如何用文件:open( )

1.3.1 控制文件读写内容的模式:t和b

强调: t和b不能单独使用,必须跟r/w/a连用,默认就是t, t代表text,通常不写

t文本(默认的模式)

  1. 读写都以str(unicode)为单位
  2. 文本文件
  3. 必须指定encoding='utf-8'

b二进制/bytes

  • 一般是一些音频文件或者视频文件

1.3.2 控制文件读写操作的模式

  • r 只读模式
  • w 只写模式
  • a 只追加写模式
  • +: r+, w+, a+ 在原来模式的基础上只读的变可读可写,可写的变可写可读

2. 文件操作的基本流程

2.1 打开文件

open("文件路径")
open("C:\a\b\c\d.txt")  # 但是\(右斜杠)在字符串中转义的作用
                        # 如果文件夹叫nb,那写成路径\nb在字符串中就是换行符的意思了

2.1.1 如何取消转义?

  • 字符串前+r,eg:r"C:\a\b\nb\d.txt"
  • 用左斜杠代替右斜杠,open功能自动会把左斜杠替换成右斜杠

2.1.2 路径分割符

  • win下默认的路径分隔符是右斜杠\
  • linux下默认的路径分隔符是左斜杠/

2.1.3 绝对路径和相对路径

绝对路径就是文件的全部路径,从开始的盘符一直写到该文件。

open(r'E:\project\python\s29code\day11\1.打开文件.py')

相对路径就是以当前文件所在的文件夹为基础,然后找文件,所以也只能找到同文件夹下的文件

image-20200811163302623

2.2 操作文件

# 1. 打开文件,由应用程序向操作系统发起系统调用open(...),
#    操作系统打开该文件,对应一块硬盘空间,并返回一个文件对象赋值给一个变量f
f=open('a.txt',moder='r',encoding='utf-8') #默认打开模式就为r

# 2. 调用文件对象的读/写方法,会被操作系统转换为读/写硬盘的操作
data=f.read()  # 读取文件内容,将硬盘中的二进制数据读取到内存中 --> t控制将二进制转换成字符

image-20200811164602250

2.3 关闭文件

打开一个文件包含两部分资源:应用程序的变量f和操作系统打开的文件。在操作完毕一个文件时,必须把与该文

件的这两部分资源全部回收,回收方法为:

1、f.close() #回收操作系统打开的文件资源,一旦关闭就不能操作了,但是f变量还在
2、del f #回收应用程序级的变量,一般我们不用写。

其中del f一定要发生在f.close( ) 之后,否则就会导致操作系统打开的文件无法关闭,白白占用资源, 而python

自动的垃圾回收机制决定了我们无需考虑del f,这就要求我们,在操作完毕文件后,一定要记住f.close( )。

2.4 with上下文管理器

with上文帮你打开文件,下文就是帮你自动关闭文件.

with open('a.txt',mode='rt') as f1:
    res = f1.read()   # 读取文件内容,硬盘的搬运工
    print(res)

# f1称之为文件对象/文件句柄,就是用来控制文件的
# 当with语句的代码块执行完毕后会自动执行f.close()
# 打开多个文件
with open('a.txt',mode='rt') as f1,open('b.txt',mode='rt') as f2:
#with open('a.txt',mode='rt') as f1,\
#   open('b.txt',mode='rt') as f2:   通过右斜杠将一句代码换行写
    res1 = f1.read()   # 读取文件内容
    res2 = f2.read()   
    print(res1)
    print(res2)

2.5 指定操作文件的字符编码

open功能还有一个参数就是encoding='解码格式'

with open(r'a.txt', mode='rt',encoding='utf-8') as f1:
    res = f1.read()   # t模式会将f.read()读出来的结果解码成unicode
    print(res, type(res))
    
    
# 内存: utf-8格式的二进制 ----> 解码 ---->  unicode
# 硬盘(a.txt内容: utf-8格式的二进制)

如果你不指定encoding参数的话,操作系统会使用自己的默认编码进行解码。

  • mac/linux utf-8
  • windows gbk

3. 文件的操作模式

3.1 控制文件操作的三种模式

r(默认的):只读
w:只写
a:只追加写

3.1.1 r 模式的使用

r (默认的操作模式):只读模式,当文件不存在时,会报错。

with open(r'd.txt', mode='rt',encoding='utf-8') as f1:
    res = f1.read()
    print(res, type(res))
    
# 运行结果:
Traceback (most recent call last):
  File "E:/project/python/s29code/day11/2.r模式.py", line 1, in <module>
    with open(r'd.txt', mode='rt',encoding='utf-8') as f1:
FileNotFoundError: [Errno 2] No such file or directory: 'd.txt'

当文件存在时,文件指针跳到开始位置,所以当我们f.read()时会把文件指针从头读到尾,即一次性

把文件内容全部从硬盘加载到内存中。注意:大文件不能这样读,如果内容过大,会撑爆内存

# a.txt
你好啊

with open(r'a.txt', mode='rt',encoding='utf-8') as f1:
    res = f1.read() # 把所有内容从硬盘读入内存
    print(res) # 你好啊  

3.1.2 w模式的使用

w模式,是只写模式,当文件不存在的时候,用w模式打开的话,会自动在该路径创建一个新的文件。

当文件存在时,w模式会先清空原来的内容,指针位于开始位置,然后再写内容。

with open(r'e.txt', mode='w',encoding='utf-8') as f1:
    f1.write("你好")

注意:w模式不是覆盖,可以自己尝试一下,假设原文件的内容很多,你用w模式打开,然后只写一个字符

试试。

image-20200819165616241

image-20200819165629041

image-20200819165648668

但是如果我们用w模式没有关闭,连续写入内容的话,不会清空之前的内容,并紧跟在旧的内容后面。

with open('b.txt',mode='w',encoding='utf-8') as f:
    f.write('大笨蛋\n')
    f.write("大傻子\n")
    f.write("二杆子")
    
# b.txt
大笨蛋
大傻子
二杆子

3.1.3 a模式的使用

a模式是只追加写模式,当文件不存在时,和w模式一样,会创建新文件。

当文件存在的时候,a模式打开文件,不会清空原文件的内容,指针会自动移到文件末尾。

with open('c.txt',mode="a",encoding="utf-8") as f:
    f.write('我是第一行\n')
    
# c.txt
我是第一行

当文件没有关闭的情况,用a模式持续写入的话,是和w模式一样的,新内容会紧跟旧内容的后面

with open('c.txt',mode="a",encoding="utf-8") as f:
    f.write('我是第一行\n')
    f.write('我是第二行\n')
    f.write('我是第三行\n')
    f.write('我是第四行\n')
    
# c.txt
我是第一行
我是第二行
我是第三行
我是第四行

a模式和w模式的异同点:

  • 相同点:只能写,不能读,当文件没有关闭时,连续写入,新内容紧跟在就内容之后
  • 不同点:a模式打开已存在的文件,不会清空原文件内容,指针自动移动到文件末尾

w模式和a模式的应用场景:

  • w模式一般用于新文件的保存,比如copy文件底层就是把一个文件读出来,然后用w写入到新文件

  • a模式则是适用于在原文件的基础上写新内容,比如记录日志,用户注册记录文件

3.1.4 了解+模式

+模式,不能单独使用,只能和r,w或a模式一起使用

  • r+ 读写模式,基准是r模式,当文件不存在时,用r+打开会报错,指针在开头。
  • w+ 写读模式,基准是w模式,文件不存在会创建文件,文件存在同样会清空原文件
  • a+ 追加读模式,基准是a模式,文件不存在会创建文件,指针在末尾

3.1.5 提一嘴x模式

x模式,只写模式,当文件不存在的时候会创建新文件,指针在文件开头,但是当文件存在的时候会直接报错

# d.txt 已经存在的文件
with open('d.txt',moder="x",encoding="utf-8") as f:
    f.write("你好")

Traceback (most recent call last):
  File "E:/project/python/s29code/day11/5.x模式.py", line 1, in <module>
    with open('d.txt',mode='x',encoding='utf-8') as f:
FileExistsError: [Errno 17] File exists: 'd.txt'    

3.2 控制文件内容的两种模式

大前提: tb模式均不能单独使用,必须与r/w/a之一结合使用
t(默认的):文本模式

  1. 读写文件都是以字符串( unicode )为单位的
  2. 只能针对文本文件
  3. 必须指定encoding参数

b:二进制模式:

  1. 读写文件都是以bytes/二进制为单位的
  2. 可以针对所有文件
  3. 一定不能指定encoding参数

3.2.1 t 模式

# t 模式:如果我们指定的文件打开模式为r/w/a,其实默认就是rt/wt/at
 with open('a.txt',mode='rt',encoding='utf-8') as f:
     res=f.read() 
     print(type(res)) # 输出结果为:<class 'str'>

 with open('a.txt',mode='wt',encoding='utf-8') as f:
     s='abc'
     f.write(s) # 写入的也必须是字符串类型

#强调:t 模式只能用于操作文本文件,无论读写,都应该以字符串为单位,而存取硬盘本质都是二进制的形式,当指定 t 模式时,内部帮我们做了编码与解码

# 如果我们用t模式打开视频文件的话
with open('a.mp4',mode='rt',encoding='utf-8') as f:
    ...   # ...  == pass 这样并不会报错,因为我们只是调用了操作系统的接口,告诉他用rt打开文件
          # 以后用utf-8对读入内存的文件进行解码,但是我们还没有读/写文件,只是打开文件,所以不报错

3.2.2 b模式

同样b模式也是不能单独使用的,必须和r、w、a配合使用,t模式只针对字符文件,而b模式是针对所有文件,包

包括文本文件,但是一定要注意不能指定encoding参数,否则报错。

with open('a.jpg',mode='rb') as f:
    res = f.read()   # 硬盘的二进制读入内存->b模式下,不做任何转换,直接读入内存
    print(res,type(res)) # bytes类型 -> 当成二进制
    # b'\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x0C
    # <class 'bytes'>
    
# 理论上我们应该读出来的是物理层间的010101这种,但是如果以这种显示的话,不利于阅读,以及操作数据
# 所以python对读出来的内容做了转换,是16进制的显示,平常我们就把当成二进制来看就行了.
with open('b.txt',mode='rb') as f:
    res = f.read()       # 把躺在硬盘的二进制直接读出来,不做任何转换
    print(res,type(res)) 
    print(res.decode('utf-8')) # 文件是以utf-8编码格式存的,可以进行字符解码

4. 循环读取文件的两种方式

4.1 for循环一行一行的读

for循环不但可以循环那些基础数据类型,也可以循环文件句柄, 每次循环,以行为单位

但是for循环有个局限

# t模式
with open('b.txt',mode='r',encoding='utf-8') as f:
    for line in f:
        print(line)
        

# 打印内容:        
# 是可拨打发红包测

# 我付款金额日本

# 费劲儿家人
# b模式
with open('b.txt',mode='rb') as f:
    for line in f:
        print(line)
        

# 打印内容:
b'\xe6\x98\xaf\xe5\x8f\xaf\xe6\x8b\xa8\xe6\x89\x93\xe5\x8f\x91\xe7\xba\xa2\xe5\x8c\x85\xe6\xb5\x8b\r\n'  # \r\n --> 换行符
b'\xe6\x88\x91\xe4\xbb\x98\xe6\xac\xbe\xe9\x87\x91\xe9\xa2\x9d\xe6\x97\xa5\xe6\x9c\xac\r\n'
b'\xe8\xb4\xb9\xe5\x8a\xb2\xe5\x84\xbf\xe5\xae\xb6\xe4\xba\xba\r\n'
b'\xe4\xbb\x98\xe9\x87\x91\xe9\xa2\x9d\xe6\x97\xa5\xe5\x93\xa6\xe5\x9b\x9e\xe9\xa1\xbe'

4.2 while循环

之前就说过for循环能实现的,while循环也能实现,循环读取文件也是可以的

# t模式和b模式都适用
with open('b.txt',mode='rb') as f:
    while 1:
        content = f.read(1024) # 可以指定读取文件内容的大小,以字节为单位
        if not content:
            break
        print(content)

4.3 小练习

文件拷贝小程序,要求:字符文件和文本文件都适用。5.

file_path = input('请输入要拷贝的文件的绝对路径:')
new_file_path = input('请输入新文件的绝对路径:')
with open(file_path, mode='rb') as f, \
        open(new_file_path, mode='wb') as f1:
    for line in f:
        f1.write(line)

5. f 的常用方法

5.1 必须掌握

# 读操作
f.read()  # 读取所有内容,执行完该操作后,文件指针会移动到文件末尾
f.readline()  # 读取一行内容,光标移动到第二行首部
f.readlines()  # 读取每一行内容,作为一个元素存放于列表中

# 强调:
# f.read()与f.readlines()都是将内容一次性读入内容,如果内容过大会导致内存溢出,若还想将内容全读入内存,则必须分多次读入,有两种实现方式:
# 方式一
with open('a.txt',mode='rt',encoding='utf-8') as f:
    for line in f:
        print(line) # 同一时刻只读入一行内容到内存中

# 方式二
with open('1.mp4',mode='rb') as f:
    while True:
        data=f.read(1024) # 同一时刻只读入1024个Bytes到内存中
        if len(data) == 0:
            break
        print(data)

# 写操作
f.write('1111\n222\n')  # 针对文本模式的写,需要自己写换行符
f.write('1111\n222\n'.encode('utf-8'))  # 针对b模式的写,需要自己写换行符
f.writelines(['333\n','444\n'])  # 迭代的将列表的元素写入文件
f.writelines([bytes('333\n',encoding='utf-8'),'444\n'.encode('utf-8')]) #b模式

5.2 了解操作

f.readable()  # 文件是否可读
f.writable()  # 文件是否可读
f.closed    # 文件是否关闭
f.encoding  # 如果文件打开模式为b,则没有该属性
f.flush()   # 立刻将文件内容从内存刷到硬盘,一般情况下当所有写操作完毕后,才会写入硬盘,但是我们             # 可以用flush强制写到硬盘
f.name      # 返回文件名称

6. 文件指针的移动

f.seek(n,模式) n指的是移动的字节个数

f.tell( ) 返回文件指针当前位置

指针移动的单位都是以字节(bytes)为单位

只有一种情况特殊:
t模式下的read(n) n代表字符的个数

强调: t模式下只能用0模式,b模式下0,1,2都可以用

6.1三种模式

模式:
0:参照物是开头位置
1:参照物是当前位置
2:参照物是文件末尾

6.1.1 0模式

with open(r'a.txt', mode='rt', encoding='utf-8') as f:
    f.seek(6, 0)
    f.seek(3,0)
    # f.seek(3, 1) # 报错
    res = f.read()
    print(res)

6.1.2 1模式

with open(r'a.txt', mode='rb') as f:
	f.seek(6, 1)
	f.seek(3,1)
    #f.seek(300, 1)  # 向右可以无限移动
    # print(f.read())
    res = f.tell()
    print(res)

6.1.3 2模式

with open(r'a.txt', mode='rb') as f:
    f.seek(-6, 2)
    f.seek(-3, 2)
    # f.seek(-30, 2) # 超过了最大的移动距离

    # f.seek(0, 0)
    # f.seek(-1, 0) # 报错,开头无法再向左移动了
    
    res = f.tell() # 返回文件指针的时候都是从左向右数
    print(res)

6.1.4 小作业

# 写一个动态更新显示最新日志的一个小程序
import time

with open(r'a.txt', mode='rb') as f:
    # 将指针跳到文件末尾
    f.seek(0, 2)
    while 1:
        res = f.readline()
        if len(res) == 0:
            time.sleep(0.5)
        else:
            print(res.decode(), end='')
            
# 追加日志的程序
with open(r'a.txt',mode='a+',encoding='utf-8') as f:
    f.write('20201120 张三消费1000元\n')

6.2 修改文件的两种方式

首先补充一个知识点,就是硬盘的数据是不能修改的,内存的数据是可以修改的。比如有一个文本文件,里面有

数据:张三 北京大学 大一学生,你想修改成 张三 男 20 北京大学 大一学生。平常我们用的文本编辑器是可以

直接修改的。但是你用python代码试一下看一下结果。

with open(r'a.txt',mode='r+t',encoding='utf-8') as f:
    f.seek(10,0) # 指针移动到张三后面
    f.write('男 20')

# 当你再次打开文件你会发现 男 20会把北京大学覆盖了

原因是硬盘不支持修改,或者说成是追加。如果一块数据发生移动,那么在它后面的所有数据都会移动,那么每次

修改文件都会产生这种问题。所以硬盘只能写不能中间插入。而我们平常用的文本编辑器只是把内存中的所有修改

后的数据再保存到硬盘上。

6.2.1 第一种方式:

with open( 'c.txt' ,mode='rt',encoding='utf-8' ) as f:
	res = f.read ( )
	data = res.replace( 'alex' , 'dsb')
    print(data)
with open( 'c.txt' ,mode='wt',encoding='utf-8' ) as f1:
	f1.write(data)

6.2.2 第二种方式:

import os

with open(r'c.txt', mode='r', encoding='utf-8') as f, \
        open(r'.c.txt.swap', mode='w', encoding='utf-8') as f1:
    # .原文件名.swap 是linux中的临时交换的文件命名
    for line in f:
        data = line.replace('alex', 'dsb')
        f1.write(data)
os.remove('c.txt')  # 删除原文件
os.rename('.c.txt.swap', 'c.txt')  # 对新文件重命名
posted @ 2020-11-22 17:00  Mn猿  阅读(220)  评论(0编辑  收藏  举报