Python 以优雅的姿势 操作文件

时间:2021-2-27 作者:admin

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 区分二进制 和 文本,那么又分为文本模式 和 二进制模式

文本模式

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

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

二进制模式

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

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


使用 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文档时,会发现在其相对路径下会生成一个隐藏文件,命名通常是以~$开头,后面跟着文件名
Python 以优雅的姿势 操作文件Python 以优雅的姿势 操作文件
替换文件
那么,在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)
    

7 > 如果删除非空文件夹,会出现 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

判断文件是否存在

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("写入内容")

拼接路径

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

获取根路径

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

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

判断文件夹是否存在

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

扩展:文件编码知识

ASCII

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

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


ASCII 码对照表

Python 以优雅的姿势 操作文件
大写字母 A 对应的编码是65,小写字母 a 对应编码是97,数字 1 对应的编码是 49
这些都可以通过 Python内置函数 ord() 进行查看

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

GB2312 & GBK

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

可以在 命令提示符 中的属性 看到Windos平台 默认的编码
Python 以优雅的姿势 操作文件
Unicode

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

特点:

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

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

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

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

对比表

依据 出现时间 排序

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

相关博客

声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。