Python——文件处理

文件

什么是文件

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

为什么要用文件

  • 用户/应用程序可以通过文件将数据永久保存到硬盘中,即操作文件就是操作硬盘。
  • 用户/应用程序直接操作的是文件,对文件进行的所有操作都是在向操作系统发送系统调用,然后再由操作系统将其转换成具体的硬盘操作

如何用文件

  • 控制文件读写内容的模式:t和b, 强调:t和b不能单独使用,必须跟r/w/a连用

    # t文本(默认的模式)
    '''
    	1.读写都以str(unicode)为单位的
    	2、文本文件
    	3、必须指定encoding="存入硬盘时的编码格式"
    '''
    # b二进制/bytes
    
  • 控制文件读写操作的模式:r/w/a/+

  • open()的使用

一、文件操作的基本流程

1.1 基本流程

  • 打开文件

    # windows路径分隔符问题
    # open('C:\a\nb\c\d.txt')
    # 解决方案一:推荐
    open(r'C:\a\nb\c\d.txt')
    # 解决方案二:
    open('C:/a/nb/c/d.txt')
    
    # 相对路径,从当前路径下开始找,如果文件不存在,则报错
    f=open('a.txt')
    # f的值是一种变量,占用的是应用程序的内存空间,向操作系统发送系统调用并在操作系统中打开资源空间
    print(f) # 文件类型
    
  • 读/写文件

    # 应用程序对文件的读写请求都是在向操作系统发送系统调用
    # 然后由操作系统控制硬盘把输入读入内存,或者写入硬盘
    res = f.read() # 读文件
    print(res)
    
    f.write("写入内容") # 写文件
    
  • 关闭文件

    f.close() # 回收操作系统资源
    f.read() # 变量f存在,但是不能再读了
    
    # del f # 回收应用程序资源
    

1.2 资源回收与with上下文管理

# with会在子代码块全部执行完毕后自动执行.close()来关闭文件
# 文件对象又称文件句柄
with open('a.txt', mode='rt') as f1:
    res = f1.read()
    print(res)
    
with open('a.txt', mode='rt') as f1,\
	open('b.txt',mode='rt') as f2:
    res1 = f1.read()
    res2 = f2.read()
    print(res1)
    print(res1)

1.3 指定操作文本文件的字符编码

# 没有指定encoding参数,操作系统会使用自己默认的编码
# linux系统默认:utf-8
# mac系统默认:utf-8
# windows系统默认gbk
with open('c.txt', mode='rt', encoding='utf-8') as f:
    # 读文件
    res = f.read() # 因为t模式的影响,会将f.read()读出的结果解码成unicode
    print(res,type(res))
    # 写文件,t模式有局限性,就是只限于文本文件
    f.write('哈哈哈')
    
# 内存:utf-8格式的二进制———————解码———————》unicode
# 硬盘(c.txt内容:utf-8格式的二进制)

二、文件的操作模式

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

  • 2.1.1 案例一:r 模式的使用

    # 登陆验证功能
    inp_user = input(">>>>your name:").strip()
    inp_pwd = input(">>>>your password:").strip()
    with open('user.txt', mode='rt', encoding='utf-8') as f:
        for line in f:
            username, password = line.strip().split(':')
            if inp_user == username and inp_pwd == password:
                print('login success')
                break
        else:
            print('账号或密码错误')
        
    
  • 2.1.2 案例二:w 模式的使用

    # w模式用来创建全新的文件
    # 文本文件的拷贝工具
    src_file = input('源文件路径>>:').strip()
    copy_file = input('源文件路径>>:').strip()
    with open(r'{}'.format(src_file), mode='rt', encoding='utf-8') as f1,\
    	open(r'{}'.format(copy_file), mode='wt', encoding='utf-8') as f2:
        # res = f1.read()
        # f2.write(res)
        for line in f1:
            f2.write(line)
    
  • 2.1.3 案例三:a 模式的使用

    # a模式用来再原有的文件内容的基础之上写入新的内容,比如记录日志
    # 注册功能
    name = input('>>>>your name:').strip()
    pwd = input('>>>>your password:').strip()
    with open('db.txt', mode='at', encoding='utf-8') as f:
        f.write('{name}:{pwd}\n'.format(name,pwd))
    
  • 2.1.4 案例四:+ 模式的使用(了解)

    # +不能单独使用,必须配合r、w、a
    with open('g.txt',mode='r+t',encoding='utf-8') as f:
        # print(f.read())
        f.write('中国')
    
    with open('g.txt',mode='w+t',encoding='utf-8') as f:
        f.write('111\n')
        f.write('222\n')
        f.write('333\n')
        print('====>',f.read())
    
    
    with open('g.txt',mode='a+t',encoding='utf-8') as f:
        print(f.read())
    
        f.write('444\n')
        f.write('5555\n')
        print(f.read())
    

2.2 控制文件读写内容的模式

  • 2.2.1 案例一:t 模式的使用

    # t模式的存操作
    '''
    	1、读写都以字符串(unicode)为单位
    	2、只能针对文本文件
    	3、必须指定encoding字符编码
    '''
    # 1、r(默认的操作模式):只读模式,当文件不存在时报错,当文件存在时文件指针跳到开始位置
    with open('r.txt', mode='rt', encoding='utf-8') as f:
        print('第一次读'.center(50,'*'))
        res = f.read() # 把所有内容从硬盘读入内存
        print(res)
        
        print('第二次读'.center(50,'*'))
        res1 = f.read() # 把所有内容从硬盘读入内存
        print(res1)
    
    # 2、w:只写模式,当文件不存在时会创建空文件,当文件存在时会清空文件,指针位于开始位置
    '''
    强调1:
    强调2:如果重新以w模式打开文件,则会清空文件内容
    '''
    with open('w.txt', mode='wt', encoding='utf-8') as f:
        f.write('哈哈哈\n')
        f.write('哈哈哈\n')
        f.write('哈哈哈\n')
        
    # 3、a:只追加写,在文件不存在时会创建空文档,在文件存在时文件指针会直接跳到末尾
    with open('w.txt', mode='at', encoding='utf-8') as f:
        f.write('哈哈哈\n')
        f.write('哈哈哈\n')
        f.write('哈哈哈\n')
    
    '''
    强调w模式与a模式的异同:
    相同点:再打开的文件不关闭的情况下,连续的写入,新内容总会跟在前写的内容之后
    不同点:以a模式重新打开文件,不会清空原文件内容,会将文件指针直接移动到文件末尾
    '''   
    
  • 2.2.2 案例二: b 模式的使用四 操作文件的方法

    # 错误演示
    with open(r'a.mp4', 'rt') as f:
        f.read()
        
    # b: binary模式
    '''
    	1、读写都是以bytes为单位
    	2、可以针对所有文件
    	3、一定不能指定字符编码
    '''
    with open(r'a.mp4', 'rb') as f:
        f.read()
        
    
    # bytes=>二进制
    '''
    得到bytes类型的三种方式
    	1、字符串编码之后的结果
    		'上'.encode('utf-8')
    		bytes('上', encoding='utf-8')
    	2、b'必须是纯英文字符'
    	3、b模式下打开文件,f.read()读出的内容
    '''
        
        
        
    # 文件拷贝工具
    src_file = input('请输入源文件路径:').strip()
    copy_file = input('请输入文件保存的路径:').strip()
    file_name = src_file.split('\\')[-1]
    with open(r'{}'.format(src_file), 'rb') as rf,\
        open(r'{src}\{copy}'.format(src=copy_file, copy=file_name), 'wb') as wf:
        for line in rf:
            wf.write(line)
            
    # 循环读取文件
    # 方式一:自己控制每次读取的数据量
    with open(r'test.jpg', 'rb') as f:
        while True:
            res = f.read(1024) # 一次只读1024个字节
            if len(res) == 0:
                break
            print(len(res))
            
    # 方式二:以行为单位,一次读取一行的数据
    with open(r'test.jpg','rb') as f:
        for line in f:
            print(line)
    
  • 2.2.3 x模式(控制文件操作的模式)了解

    # x, 只写模式【不可读;不存在则创建,存在则报错】
    
  • 总结:

    1. 在操作纯文本文件方面t模式帮我们省去了编码与解码的环节,b模式则需要手动编码与解码,所以此时t模式更为方便
    2. 针对非文本文件(如图片、视频、音频等)只能使用b模式

三、操作文件的方法

3.1 重点

# 一:读相关操作
# 1、readline:一次读一行
with open(r'test.txt', 'rt', encoding='utf-8') as f:
    while True:
        line = f.readline()
        if len(line) == 0:
            break
        print(line)
        
# 2、readlines:
with open(r'test.txt', 'rt', encoding='utf-8') as f:
    while True:
        line = f.readlines()
        print(line)
'''
强调:
f.read()与f.readlines()都是将内容一次性读入内容,如果内容过大会导致
'''

# 二:写相关操作
# 3、f.writelines():
with open(r'test.txt', 'wt', encoding='utf-8') as f:
    # f.write('1111\n222\n3333\n')
    # l=['1111\n', '2222', 3333] # 会报错,应为是t模式,必须是str类型
    l=['1111\n', '2222', '3333']
    # for line in l:
    #     f.write(line)
    f.writelines(l)
    
with open(r'test.txt', 'wb') as f:
    # 补充1:纯英文字符,可以不做转换通过加前缀b得到bytes类型
    l=[b'1111\n', b'2222', b'3333']
    
    # 补充2:'上'.encode('utf-8')等同于bytes('上',encoding='utf-8')
    l=['矮跟'.encode('utf-8'), '大'.encode('utf-8'), 'SB'.encode('utf-8')]
    l=[
        bytes('矮跟',encoding='utf-8'),
        bytes('大',encoding='utf-8'),
        bytes('SB',encoding='utf-8')
    ]
    f.writelines(l)
# 4、flush (大多数情况不用)
with open(r'test.txt', 'wt', encoding='utf-8') as f:
    f.write('哈哈哈')
    f.flush() # 告诉操作系统,强制立刻将数据写入内存

3.2 了解

with open(r'test.txt', 'wt', encoding='utf-8') as f:
    print(f.readable())  # 文件是否可读
    print(f.writable())  # 文件是否可写
    print(f.closed)      # 文件是否关闭
	print(f.encoding)    # 如果文件打开模式为b,则没有该属性
	print(f.flush())     # 立刻将文件内容从内存刷到硬盘
	print(f.name)        # 获取文件名

四、主动控制文件内指针移动

'''
指针移动的单位都是以bytes/字节为单位
只有一种情况下特殊:
	t模式下的read(n),n代表的是字符个数
'''
with open('test.txt', 'rt', encoding='utf-8') as f:
    res=f.read(4)
    print(res)
    
# f.seek(n,模式):n指的是移动的字节个数
# 模式0:参照物是文件开头位置
f.seek(9,0) # 9
f.seek(3,0) # 3
# 模式1:参照物是当前指针所在位置
f.seek(9,1) # 9
f.seek(3,1) # 12
# 模式2:参照物是文件末尾位置,应该倒着移动
f.seek(-9,2) # 3
f.seek(-3,2) # 9

'''
强调:只有0模式可以在t下使用,1、2必须在b模式下使用
'''

# f.tell() # 获取文件指针当前位置

4.1 案例一:0模式详解

with open('test.txt',mode='rb') as f:
    f.seek(9,0) # 9
    f.seek(3,0) # 3
    # print(f.tell())
    f.seek(4,0) # 4
    res=f.read()
    print(res.decode('utf-8'))

4.2 案例二:1模式详解

with open('test.txt',mode='rb') as f:
    f.seek(9,1) # 9
    f.seek(3,1) # 12
    print(f.tell())

4.3 案例三:2模式详解

with open('test.txt',mode='rb') as f:
    f.seek(-9,2)
    # print(f.tell())
    f.seek(-3,2)
    # print(f.tell())
    print(f.read().decode('utf-8'))

4.4 f.seek的应用(tail -f accsee.log程序讲解)

# 追写文件内容的程序test.py
with open(r'access.log', 'at', encoding='utf-8') as f:
    f.write('202003111112 egon转账200w\n')
    
# 监测追写内容的程序tail.py
import time
with open(r'access.log', 'rb') as f:
    f.seek(0, 2)
    while True:
        line = f.readline()
        if len(line) == 0:
            time.sleep(0.3)
        else:
            print(line.decode('utf-8'), end='')

五、文件的修改

# 文件a.txt内容如下
张一蛋     山东    179    49    12344234523
李二蛋     河北    163    57    13913453521
王全蛋     山西    153    62    18651433422

# 执行操作
with open('a.txt',mode='r+t',encoding='utf-8') as f:
    f.seek(9)
    f.write('<妇女主任>')

# 文件修改后的内容如下
张一蛋<妇女主任> 179    49    12344234523
李二蛋     河北    163    57    13913453521
王全蛋     山西    153    62    18651433422

# 强调:
# 1、硬盘空间是无法修改的,硬盘中数据的更新都是用新内容覆盖旧内容
# 2、内存中的数据是可以修改的

5.1 文件修改方式一

# 文本编辑器采用的就是这种方式
# 实现思路:将文件内容发一次性全部读入内存,然后在内存中修改完毕后再覆盖写回原文件
# 优点: 在文件修改过程中同一份数据只有一份
# 缺点: 会过多地占用内存
with open('db.txt',mode='rt',encoding='utf-8') as f:
    data=f.read()

with open('db.txt',mode='wt',encoding='utf-8') as f:
    f.write(data.replace('kevin','SB'))

5.2 文件修改方式二

# 实现思路:以读的方式打开原文件,以写的方式打开一个临时文件,一行行读取原文件内容,
# 修改完后写入临时文件...,删掉原文件,将临时文件重命名原文件名
# 优点: 不会占用过多的内存
# 缺点: 在文件修改过程中同一份数据存了两份
import os

with open('db.txt',mode='rt',encoding='utf-8') as read_f,\
        open('.db.txt.swap',mode='wt',encoding='utf-8') as wrife_f:
    for line in read_f:
        wrife_f.write(line.replace('SB','kevin'))

os.remove('db.txt')
os.rename('.db.txt.swap','db.txt')
posted @ 2020-03-13 13:47  群青-Xi  阅读(145)  评论(0编辑  收藏  举报