Python 以优雅的姿势 操作文件

Python 以优雅的姿势 操作文件


open() 方法🎏

open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)

参数如下:

  • file:文件路径(绝对路径或者相对路径),如果直接写文件名的话那就是 相对路径

  • mode:为字符串参数,用于指定打开文件的模式,默认值是 “r”,也就是读取模式,其余模式参考下面内容

  • buffering:可选的整数参数,用于设置缓冲策略,若为 0 以切换缓冲关闭(仅允许在二进制模式下),1选择行缓冲(仅在文本模式下),大于1的整数以指示固定大小的块缓冲区的大小(单位:字节),如果没有给出参数,默认缓冲策略的工作方式如下:

    • 二进制文件以固定大小的块进行缓冲;使用启发式方法选择缓冲区的大小,尝试确定底层设备的“块大小”或使用 io.DEFAULT_BUFFER_SIZE。在大多数系统上,缓冲区的长度通常为 4096 或 8192 字节。
    • “交互式”文本文件( isatty() 返回 True 的文件)使用行缓冲。其他文本文件使用上述策略用于二进制文件。
  • encoding:指定用于解码或编码文件时 所 编码的名称,只在文本模式下使用,默认值(默认编码类型)是根据你的操作系统平台决定的,Windows系统是默认国产的 GBK编码,Liunx 、Macos 系统 为默认 UTF-8 编码,这也是为什么在Windos平台上打开utf-8编码文件时报错的原因,这里建议 好习惯 encoding=”utf-8"

  • errors:可选字符串参数,指定如何处理编码和解码错误,不能在二进制模式下使用

    • strict :如果存在编码错误,会引发 ValueError 报错,默认值 None 具有相同的效果
    • ignore :忽略错误,但忽略编码错误可能会导致数据丢失,可能会在一些嵌入式环境中使用
    • replace :会将替换标记(例如 ‘?’ )插入有错误数据的地方
  • newline:控制 universal newlines (通用换行符)模式如何生效(它仅适用于文本模式),如果 newline 为 None,则启用通用换行模式,输入中的行可以以 ‘\n’,’\r’ 或 ‘\r\n’ 结尾,这些行被Python翻译成 ‘\n’ ,简单来说,就是以什么为判断内容下一行的依据,windos默认约定为 “\r\n” , Unix 为 “\n”,MacOS 为 “\r”

  • closefd:如果 closefd 是 False 并且给出了文件描述符而不是文件名,那么当文件关闭时,底层文件描述符将保持打开状态;如果给出文件名则 必须为 True(默认值,否则将引发错误

  • opener:设置自定义开启器,通过使用参数( file,flags )调用 opener 获得文件对象的基础文件描述符,开启器必须返回一个打开的文件描述符。


文件打开模式📌

模式描述文件已存在文件不存在
r 只读 方式打开文件(默认)正常读取报错 FileNotFoundError
rb 二进制格式 打开文件 用于 读取 正常读取报错 FileNotFoundError
w 只写 方式打开文件清空原有内容从头开始写入创建新文件进行写入
wb 二进制 方式打开文件 用于 写入 清空原有内容从头开始写入创建新文件进行写入
a 追加 方式打开文件新的内容将会被写入到已有内容末尾创建新文件进行写入
ab 二进制 方式打开文件 用于 追加 新的内容将会被写入到已有内容末尾创建新文件进行写入
x排它性创建 写模式创建新文件进行写入报错 FileExistsError
b不单独使用,二进制模式~~
t不单独使用,文本模式(默认)~~
U通用换行模式(Python3 已弃用~~

以 内容数据 类型为参考的话,Python 区分二进制 和 文本,那么又分为文本模式 和 二进制模式

1) 文本模式

在不指定文件模式时,默认模式为 “r”,打开用于读取文本,与 “rt” 是一样的。

文本模式下,文件内容返回为 字符串,使用 “r”,“w” 等模式时,与 后面加 “t” 相同,“r” = “rt”

2) 二进制模式

二进制模式下,返回的内容为 bytes 对象,不进行任何解码

在Python 中创建 图片、视频等文件时,就需要用到 二进制模式 写入数据内容。

其实,用的最多的还是原生的文件打开模式,r 和 w
在大部分情况下,这两种模式相互配合使用就已经够了


使用 with 语句💡

在使用 open() 内置函数 操作文件时,得记得在操作结束后加上一句 f.close()

每次操作完都得加上 f.close() ,显得有些麻烦,且如果在操作完忘记加上这一句话,还会造成资源一直占用的问题
于是,这里 推荐使用 with 语句 来提升编写代码的效率

普通写法

f = open("中文.txt", "r", encoding="utf-8")
data = f.read()
print(data)
f.close()

使用 with 语句

with open("中文.txt", "r", encoding="utf-8") as f:
    data = f.read()
    print(data)

优点:

  • 提升代码阅读性
  • 减少代码冗余,免去 f.close() 步骤,同时也防止忘记关闭文件调用

接下来的代码,我将统一使用 with 语句演示


创建文件

创建文件,常用的 文件打开模式是 “w”,当然也可以使用 “x” 模式,前提是你所指定的目录下没有这个文件

只是创建一个空白文件的话 可以这么写

with open("文件.txt", "w", encoding="utf-8") as f_w:
    pass

创建多个文件 可以配合循环

for i in range(1, 5):
    with open(f"文件_{i}.txt", "w", encoding="utf-8") as f_w:
        pass

创建文件 并且 写入内容

with open(f"文件.txt", "w", encoding="utf-8") as f_w:
    f_w.write("hello word")

读取文件

读取文件,用到的 文件打开模式是 “r”

  • .read(size = -1)*
    读取全部

    • size : 指定读取的字节数, 默认值-1表示读取整个文件


    读取全部内容

    with open(f"中文.txt", "r", encoding="utf-8") as f_w:
        data = f_w.read()           # 读取所有内容
        print(data)
    

    利用 size 参数 在特点场合下有妙用

    with open(f"中文.txt", "r", encoding="utf-8") as f_w:
        while True:
            data = f_w.read(10)         # 每次只读取10个字节
            if data:
                print(data)
            else:
                break
    
  • .readline(size = -1)
    读取一行

    • size : 指定中读取的字节数, 默认值-1表示读取一行内容, 用法与上面 .read() 相同


    读取一行

    with open(f"中文.txt", "r", encoding="utf-8") as f_w:
        data = f_w.readline()
        print(data)
    

    一行一行方式读取 全部内容

    with open(f"中文.txt", "r", encoding="utf-8") as f_w:
        while True:
            data = f_w.readline()
            if not data:
                break
            print(data)
            
    # 还可以直接循环文件对象实现
    with open(f"中文.txt", "r", encoding="utf-8") as f_w:
        for line in f_w:
            print(line)
    

.readline(size = -1)
读取所有行,并返回列表,每一行为列表中的一个值

with open(f"中文.txt", "r", encoding="utf-8") as f_w:
    data_list = f_w.readlines()
    print(data_list)

增加内容(末尾)

对文件内容进行追加,用到的 文件打开模式是 “a”

追加的内容会写在文件末尾

with open("中文.txt", "w", encoding="utf-8") as f_w:		# 创建初始文件
    f_w.write("我是第一行内容\n")

with open("中文.txt", "a", encoding="utf-8") as f_a:		# 追加文件内容
    f_a.write("我是追加的内容")

这个模式用在写简单的 程序运行 日志 上


修改文件内容(重点)🧬

需要使用到两种 文件打开模式 进行配合,先读(“r”)后写(“w”)

原理:
很简单,就是先将 内容读取 到内存,然后对读取到的数据进行修改、增加、删除等操作,再重新写入到新文件中,再把旧文件替换成新文件在编辑过程未结束的情况下 产生的新文件可以理解为 临时文件,此时尚未与旧文件替换

这种修改方式其实很常见,拿我们常用的 word 文档来看
在平时编辑word文档时,会发现在其相对路径下会生成一个隐藏文件,命名通常是以~$开头,后面跟着文件名
word文档临时文件编辑过程中
替换文件
那么,在py中怎么替换文件呢?

这就需要用到 os 标准库模块下的 os.replace()

os.replace("新文件", "旧文件")

根据以上原理,Py实现

temp_name = r"~$"
file_name = "中文.txt"
with open(f"{temp_name}{file_name}", "w", encoding="utf-8") as f_w:
    with open(file_name, "r", encoding="utf-8") as f_r:
        data = f_r.read()
        data = data.replace("内容", "nei_rong")       # 替换操作
        data += "我是再加上的内容\n"                  # 增加内容  
        f_w.write(data)

os.replace(f"{temp_name}{file_name}", file_name)	  # 替换文件

删除文件

这里需要用到 os 标准库模块

file_path = ""
if os.path.isfile(file_path):
    os.remove(file_path)            # 只能删除文件 非文件夹

注意:只能删除文件,非文件夹,否则会出现 OSError 错误

删除文件夹

需要注意的是,文件夹分两种,一种是空文件夹,另外一种则是文件夹中有内容的 非空文件夹

  • 空文件夹:
    利用 os 标准库模块
    os.rmdir() 删除指定路径的目录,文件夹必须为空

    dir_path = ""
    if not os.listdir(dir_path):
    	os.rmdir(dir_path)
    

    如果删除非空文件夹,会出现 OSError 错误

  • 非空文件夹:

    方法一:(推荐)
    利用 shutil 标准库模块
    shutil.rmtree() 删除一个完整的目录树

    path = ""
    if os.path.isdir(path):
    	shutil.rmtree(path)     # 删除非空文件夹
    

    方法二:
    还是使用回 os 标准库模块中的功能,但这个方法比较繁琐

    for b, d, f in os.walk(path, topdown=False):        # 一定要设置 topdown 参数为False,从里层开始
    for file_n in f:
        os.remove(os.path.join(b, file_n))
    for dir_p in d:
        dir_p = os.path.join(b, dir_p)
        if not os.listdir(dir_p):
            os.rmdir(dir_p)
    else:
    	os.rmdir(path)
    

扩展:利用 OS 模块

OS 模块是个利器,操作文件时 有 OS 可以做出更厉害的操作
导入os模块

import os

1) 判断文件是否存在

os.path.isfile()  	# 判断路径是否为文件

根据文件是否存在决定写入模式

file_path = ""                  # 文件目录
if os.path.isfile(file_path):
    print("文件存在")
    with open(file_path, "a", encoding="urf-8") as f_a:
        f_a.write("写入内容")    # 追加文件中的内容 
else:
    print("文件不存在")
    with open(file_path, "w", encoding="utf-8") as f_w:
        f_w.write("写入内容")

2) 拼接路径

os.path.join()  	# 把目录和文件名合成一个路径
path = os.path.join("路径一", "路径二")

3) 获取根路径

适用于当前所运行的 py文件

BASE_DIR = os.path.dirname(__file__)    # 获取当前Py 根目录

4) 判断文件夹是否存在

os.path.isdir() 	# 判断路径是否为目录

如果文件夹不存在,则创建文件夹并在此文件夹内创建文件

BASE_DIR = os.path.dirname(__file__)                     # 获取当前Py 根目录
dir_path = [os.path.join(BASE_DIR, "我是文件夹"), ]       # 文件夹路径
file_path = os.path.join(dir_path[0], "我是文件.txt")         # 文件目录


def judg_isdir(funx):
    """
    文件夹初始化装饰器
    """
    def inner(*args, **kwargs):
        for d in dir_path:
            if not os.path.isdir(d):    # 如果文件夹不存在则创建
                os.mkdir(d)
        return funx(*args, **kwargs)
    return inner


@judg_isdir
def mydir():
    if os.path.isfile(file_path):   # 如果文件存在
        print("文件存在")
        with open(file_path, "a", encoding="urf-8") as f_a:
            f_a.write("写入内容")    # 追加文件中的内容
    else:
        print("文件不存在")
        with open(file_path, "w", encoding="utf-8") as f_w:
            f_w.write("写入内容")


mydir()

扩展:文件编码知识

1) ASCII

ASCII (American Standard Code for Information Interchange,美国信息交换标准代码)是基于拉丁 字母 的一套编码,主要用于显示现代英语和其他西欧语言,是最通用的信息交换标准,并等同于国际标准 ISO/IEC 646
ASCII 第一次以规范标准的类型发表是在1967年,最后一次更新则是在1986年,到目前为止共定义了128个字符

由于计算机是美国人发明的,因此最早只有 ASCII 被编码到计算机里,大小写英文字母、数字和一些符号

ASCII 码对照表

在这里插入图片描述
大写字母 A 对应的编码是65,小写字母 a 对应编码是97,数字 1 对应的编码是 49
这些都可以通过 Python内置函数 ord() 进行查看

print(ord("A"))
print(ord("a"))
print(ord("1"))

2) GB2312 & GBK

GB2312 和 GBK 都为 国产编码,GB2312 于1980年 最早发布
GBK 是 GB2312 的升级版,加入更多字符,向下与 GB 2312 编码兼容国产编码,一直用到现在,Windos中文平台 默认编码依旧是 GBK

可以在 命令提示符 中的属性 看到Windos平台 默认的编码
Windows默认编码
3) Unicode

Unicode 是 ISO(国际标谁化组织)制定的可以容纳世界上所有文字和符号的字符编码,所以又俗称 万国码、统一码,解决了 传统的字符编码方案的局限(简单来说:每个国家都有自己一套的编码标准,如果跨国办公或者跨国产品,很容易出现各个国家编码不相通,造成乱码,在当时万国码没出来之前,各国之间的编码可谓是战国时期,乱码现象很常见

特点:

  • Unicode 为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理、阅读,极大改善了不同国家之间的信息传递

  • 可以跟各种语言的编码自由转换,兼容性很强,比如说用 gbk编码 的文本 ,可以转成Unicode

  • 容纳世界上所有文字和符号的字符编码

4) UTF-8

Unicode 是 字符集,UTF-8 是 编码规则

UTF-8 就是 Unicode 的实现方式,对unicode字符集进行编码的一种编码方式

在计算机内存中,使用Unicode编码,当需要保存到硬盘或者需要传输的时候,就转换为UTF-8编码
具体流程:编辑文本时,从文件读取 UTF-8 字符转换为 Unicode 字符到内存里,进行编辑操作,编辑完成后,再把内存中的 Unicode 字符 转换为UTF-8 字符 存储到文件里

注意:utf-8 不能直接于 gbk 转换,需要有 Unicode 作为中间人 过渡,这是为什么 在WIndows平台上 打开utf-8文本文件时容易出现乱码的原因

此外 还有UTF-16,UTF-32

对比表

依据 出现时间 排序

编码出现时间描述所占大小
ASCII1967年最早诞生编码,英语和西欧语言一字节
GB23121980年国产简体中文编码,兼容 ASCII 码两字节
Unicode1991年国际统一标准字符集,俗称万国码两字节
GBK1995年GB2312升级版,支持繁体,加入更多字符两字节
UTF-81992年不定长编码1 - 3 字节

相关博客😏

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值