31天Python入门——第13天:文件操作

|----------------|
| 你好,我是安然无虞。 |

文章目录

    • 文件操作
      • [1. 文件的概念](#1. 文件的概念)
      • [2. python中的文件读取](#2. python中的文件读取)
      • [3. python中的文件写入](#3. python中的文件写入)
        • [补充: 文件指针相关](#补充: 文件指针相关)
      • [4. with语句实现文件读写](#4. with语句实现文件读写)
        • [扩展学习: json相关](#扩展学习: json相关)
      • [5. 补充练习](#5. 补充练习)

文件操作

1. 文件的概念

  1. 文件的概念和分类
    • 文件是用于存储数据的一种持久化媒介.
    • 在计算机中, 文件分为文本文件和二进制文件两种类型.
    • 文本文件由字符组成, 可以使用文本编辑器打开并阅读.
    • 二进制文件由字节组成, 包含非文本数据, 如图像、音频和视频等.

在日常生活, 工作中, 文件的操作主要包括: 创建文件, 打开, 关闭, 读, 写.

2. python中的文件读取

使用 open() 函数打开文件, 接受文件路径和打开模式, 编码等作为参数.
open函数会返回一个对象,我们可以称之为文件对象.

文件的打开,分为 文本模式 和 二进制模式:

通常,对文本文件,都是以文本模式打开
文本模式打开文件后,我们的程序读取到的内容都是字符串对象,写入文件时传入的也是字符串对象.

python 复制代码
f = open(file, mode, encoding)
# file: 需要打开的目标文件(包含路径和文件名), 类型是字符串.
# mode: 设置打开文件的模式. 读, 写, 追加写. 类型是字符串.
# encoding: 编码. 一般使用utf-8.

# 使用 close() 方法关闭文件, 释放资源.
f.close()
open函数的参数

要读写文件,首先要通过内置函数open 打开文件,获得文件对象.

函数open的参数如下:

python 复制代码
open(
    file, 
    mode='r', 
    buffering=-1, 
    encoding=None, 
    errors=None, 
    newline=None, 
    closefd=True, 
    opener=None
    )

其中下面这3个参数是我们常用的:

  • 参数 file

    file参数指定了要打开文件的路径.

    可以是相对路径,比如 'log.txt', 就是指当前工作目录下面的log.txt 文件 也可以是绝对路径,比如 'd:\project\log\log.txt'

  • 参数 mode

    mode参数指定了文件打开的 模式 ,打开文件的模式 决定了可以怎样操作文件

  • 参数 encoding

    encoding 参数指定了读写文本文件时,使用的 字符编解码 方式

    调用open函数时,如果传入了encoding参数值:

    • 后面调用write写入字符串到文件中,open函数会使用指定encoding编码为 字节串;
    • 后面调用read从文件中读取内容,open函数会使用指定encoding解码为字符串对象

    如果调用的时候没有传入encoding参数值,open函数会使用系统缺省字符编码方式. 比如在中文的Windows系统上,就是使用cp936(就是gbk编码).

    建议大家编写代码 读写文本文件时,都指定该参数的值.

常见的打开模式包括: 读取模式('r')、写入模式('w')、追加模式('a')和二进制模式('b')

上述代码中的f是open函数返回的文件对象.

以下是关于文件读取的常用模式.

模式 描述
'r' 默认模式, 以只读方式打开文件.文件的指针 将会放在文件的开头 .如果文件不存在, 将会引发FileNotFoundError异常.
'rb' 以二进制模式以只读方式打开文件.适用于读取二进制数据, 如图像、音频等.
'r+' 以读写方式打开文件.文件的指针将会放在文件的开头. 这里是不会清空文件内容的. 如果文件不存在, 将会引发FileNotFoundError异常.
'rb+' 以二进制模式以读写方式打开文件.文件的指针将会放在文件的开头.如果文件不存在, 将会引发FileNotFoundError异常.
python 复制代码
# 1. 相对路径.
# 2. 绝对路径.
# f:文件对象, 它是一个迭代器.
f = open(r".\test.png", 'rb', encoding='utf-8') # 读取图片,应该是二进制数据 
content = f.read()
print(content)

f.close()
文本的读取
  1. 使用 read() 方法读取整个文本文件的内容.
  2. 使用 readline() 方法逐行读取文本文件的内容, 每次调用 readline()方法, 它会返回文件中的下一行作为一个字符串.当到达文件末尾时, 它会返回一个空字符串. 可以在循环中使用 readline() 方法来逐行处理文件内容. -> 注意换行符也读取出来了
  3. readlines(): 这个方法用于一次性读取整个文件内容, 并将每一行作为一个字符串存储在一个列表中.它会返回一个包含所有行的列表, 每行作为一个元素. 你可以直接遍历这个列表或使用索引访问特定行.

以上3个方法都可以接收一个参数,它们接受一个可选的参数用于指定要读取的字符数或字节数(是字符数还是字节数和读取的文件类型相关联), 指定要读取的最大字符数或字节数.如果省略参数或指定为负数(默认值), 则会读取全部内容.返回值是一个包含读取行内容的字符串.

python 复制代码
# f:文件对象, 它是一个迭代器.
f = open(r".\test.txt", 'r', encoding='utf-8')
content = next(f)
print(content)
for text in f:
    print(f'文件内容: {text}')
# content = f.read(10)
content = f.readline(10) # 也是根据读取的字符数来的
content = f.readline(100) # 只将当前行的内容给出, 并没有给出下一行
# 对于readline()来说, 当读取的字符数小于当前行时截断显示, 当大于时也只是显示当前行的内容

print(content)
print(content)
lines = f.readlines(57)
print(lines)
line = True
while line:
    line = f.readline()
    print(line.strip())
f.close()

3. python中的文件写入

write() : 使用 write() 方法向文本文件写入文本内容, 调用write将内容写入到缓冲区.

flush() : 调用flush()将缓冲区的内容写入到磁盘.

close() : 调用close()关闭文件的同时也会将缓冲区的内容写入到磁盘. 所以调用close()的话, 可以不需要使用到flush().
以下是关于文件写入的常用模式.

r

w

a

b

+: 可读可写

思考一下: r+ 和 a 的区别: 后面会讲解到.

模式 描述
'w' 以写入方式打开文件.如果文件已存在, 则会被清空;如果文件不存在, 则会创建一个新文件.
'wb' 以二进制模式以写入方式打开文件.适用于写入二进制数据, 如图像、音频等.
'w+' 读写方式打开文件.如果文件已存在, 则会被清空;如果文件不存在, 则会创建一个新文件.
'wb+' 以二进制模式以读写方式打开文件.如果文件已存在, 则会被清空;如果文件不存在, 则会创建一个新文件.
'a' 以追加方式打开文件.文件的指针将会放在文件的末尾.如果文件不存在, 则会创建一个新文件.
'ab' 以二进制模式以追加方式打开文件.适用于追加二进制数据.
'a+' 以读写方式打开文件.文件的指针将会放在文件的末尾.如果文件不存在, 则会创建一个新文件.
'ab+' 以二进制模式以读写方式打开文件.文件的指针将会放在文件的末尾.如果文件不存在, 则会创建一个新文件.
python 复制代码
# 写入刚刚读取到的图片(二进制数据)
f = open('./jietu.png', 'wb')
f.write(b'xxxxxx')
f.close()

# 查看是否生成了这个图片, 双击图片是否正常显示
python 复制代码
# 追加写
f = open('./text.txt', 'a')
f.write('hello world\n') # 注意这个'\n'的处理, 可以在追加写的时候自动换行
f.close()
补充: 文件指针相关

LF 和 CRLF 是两种不同的行结束符,它们在不同操作系统和场景下有着不同的用途和特点:

  • LF 是 "Line Feed" 的缩写,表示换行符. 在文本文件中,它用于表示一行的结束,并将光标移动到下一行的开头. (\n)
  • CRLF 是 "Carriage Return and Line Feed" 的缩写,表示回车符和换行符的组合。它是由两个字符组成的,先是一个回车符(CR),将光标移动到当前行的开头,然后是一个换行符(LF),将光标移动到下一行的开头. (\r\n)
python 复制代码
f = open('./test.txt', 'a')
n = f.tell() # n为当前文件指针所在的位置
print(n)

# test.txt 内容是'hello world'一行内容
# 用LF其实就是 'hello world\n'
# 用CRLF其实就是 'hello world\r\n'

# 如果将上面的'a'换成'r'的话: 打印出来的n就是0, 因为以r的方式打开文件会将文件指针放到文件的开头

现在有一个需求, 将文件中的'world'换成'python', 需要怎么做: 我们可以手动操作文件指针

python 复制代码
f = open('./test.txt', 'a')
f.seek(6) # 将指针移动到第6个字符处
f.truncate() # 截断 - 将文件指针后的字符全部截掉
f.write('python\n') # 这样就可以将原来的 hello world 改为 hello python
f.close()

4. with语句实现文件读写

with 语句可以自动管理文件的打开和关闭, 无需显式调用 close() 方法.
示例:

python 复制代码
# as关键字后面的变量f实际上就是文件对象
with open('test.txt', 'r') as f:
	content = f.read()

print(content)

使用with语句可以更安全和高效地进行文件读写操作, 并确保在读写完成后正确地关闭文件.无需手动调用close()方法.

注意:
with 语句本身不会限制变量的作用域. 变量的作用域取决于它被定义的位置(全局作用域或局部作用域)

  • 如果 with 语句块位于全局作用域中,那么在 with 语句块中定义的变量(如 content)也是全局变量,可以在整个模块中访问.
  • 如果 with 语句块位于函数内部,那么在 with 语句块中定义的变量是局部变量,只能在该函数内部访问.

所以上面的代码中可以在with语句外使用content变量.

扩展学习: json相关

JSON(JavaScript Object Notation, JS对象简谱)是一种轻量级的数据交换格式。

它基于 ECMAScript(European Computer Manufacturers Association, 欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。

易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。

  • 在Python中,JSON可以表示为字符串,因为在传输或存储时,JSON数据需要以字符串的形式进行序列化.
  • 将Python对象转换为JSON字符串以便传输或存储. 然后,在需要时,可以将JSON字符串反序列化为Python对象.

JSON的语法规则与Python中的字典(dict)非常相似,因此我们可以将Python中的字典转换为JSON格式,以便在不同的系统或应用程序之间进行数据交换.

总结起来,JSON是一种数据交换格式,可以用于表示数据,并且在Python中可以进行JSON与Python对象之间的相互转换.

  • json.loads(): 将json字符串转化为字典对象
python 复制代码
# json.loads(): 将json字符串转化为字典对象

json_string = """
{
  "name": "John",
  "age": 25,
  "xxx": null,
  "isStudent": true,
  "hobbies": ["reading", "playing", "traveling"],
  "address": {
    "street": "123 Main St",
    "city": "New York"
  },
  "scores": [85, 92, 78, 90]
}
"""

import json

data_dict = json.loads(json_string) # 将json字符串转化为字典对象
print(type(data_dict)) # <class 'dict'>
print(data_dict) # {'name': 'John', 'age': 25, 'xxx': None, 'isStudent': True, 'hobbies': ['reading', 'playing', 'traveling'], 'address': {'street': '123 Main St', 'city': 'New York'}, 'scores': [85, 92, 78, 90]}
score = data_dict.get('scores')
print(f'分数是: {score}') # 分数是: [85, 92, 78, 90]
  • json.dumps(): 将字典对象转化为json字符串
python 复制代码
# json.dumps(): 将字典对象转化为json字符串

import json

data_dic = {
    "name": "张三",
    "age": 25,
    "xxx": None,
    "isStudent": True,
    "hobbies": ["reading", "playing", "traveling"],
    "address": {
    "street": "123 Main St",
    "city": "New York"
    },
    "scores": [85, 92, 78, 90]
}
with open("./test.txt", 'w', encoding='utf8') as f:
    f.write(json.dumps(data_dic, ensure_ascii=False)) # json.dumps() 将字典对象转化为json字符串

5. 补充练习

1.实现一个通讯录的功能. 存储的联系人需要永久存储. (提示: 将联系人存储到文件.)

通讯录的基本功能都要具备.

  1. 添加联系人.
  2. 删除联系人.
  3. 查询指定联系人.
  4. 查看所有的联系人.
  5. 退出通讯录.
python 复制代码
import json

def query_all():
    with open("./contact.txt", 'r', encoding='utf8') as f:
        content = f.read()
        if content:
            # 如果存在, 就要展示所有的联系人.
            print('为您查询到的所有联系人如下:')
            json_data = json.loads(content)
            for key, val in json_data.items():
                print(f'{key}: {val}')
        else:
            print(f'该通讯录目前没有联系人, 请先添加联系人')

def query_contact():
    name = input("请输入想要查询的联系人姓名:")
    with open("./contact.txt", 'r', encoding='utf8') as f:
        content = f.read()
        if content:
            # 如果存在, 就要做查询操作.
            json_data = json.loads(content)
            phone = json_data.get(name)
            print(f'为您查询到的指定联系人{name}的电话是: {phone}')
        else:
            print(f'未找到指定联系人: {name}')

def del_contact():
    name = input("请输入想要删除的联系人姓名:")
    with open("./contact.txt", 'r+', encoding='utf8') as f:
        content = f.read()
        if content:
            # 如果存在, 就要做删除操作.
            json_data = json.loads(content)
            json_data.pop(name)
            f.seek(0)
            f.truncate()
            f.write(json.dumps(json_data, ensure_ascii=False))
        else:
            # 如果不存在, 就没办法删了.
            print(f'未找到指定联系人: {name}')

def add_contact():
    name = input("请输入联系人姓名:")
    phone = input("请输入联系人电话:")
    contact_dict = {
        name: phone
    }
    # 将联系人信息存储到文件 - 可以使用字典
    with open("./contact.txt", 'r+', encoding='utf8') as f:
        content = f.read() # 此时文件指针跑到了文件内容的末尾
        if content:
            json_data = json.loads(content)
            json_data.update(contact_dict)
        else:
            json_data = contact_dict
        # 将文件指针移动到文件开头
        f.seek(0)
        f.truncate()
        f.write(json.dumps(json_data, ensure_ascii=False))


def menu():
    print("欢迎使用通讯录管理系统")
    print("------welcome-----")
    print("菜单选项:")
    print("1. 添加联系人.")
    print("2. 删除联系人.")
    print("3. 查询指定联系人.")
    print("4. 查看所有的联系人.")
    print("5. 退出通讯录.")
    while True:
        choice = int(input("请输入您想要操作的选项:"))
        if choice == 1:
            add_contact()
        elif choice == 2:
            del_contact()
        elif choice == 3:
            query_contact()
        elif choice == 4:
            query_all()
        elif choice == 5:
            print('已退出通讯录管理系统')
            break

menu()

2.图片文件类型识别

你们公司有一批图片文件,不小心被管理人员把扩展名都去掉了.

这批图片文件中有的是png文件,有的是jpg文件.

png文件的开头一定是 这样的 89 50 4e 47 0d 0a 1a 0a 8个字节

现在要求你写一个函数,参数是图片文件的路径,函数根据文件的开头8个字节的信息,判断该文件是不是png文件.

如果是,打印出 png, 否则打印出 jpg.

python 复制代码
def tellPngFile(fp):
	f = open(fp, 'rb')
	content = f.read(8) # 只读出来文件开头8个字节即可
	f.close()
		
	if content == b'\x89\x50\x4e\x47\x0d\x0a\x1a\x0a':
		print('png')
	else:
		print('jpg')

tellPngFile('download.png')

|----------------------|
| 遇见安然遇见你,不负代码不负卿。 |
| 谢谢老铁的时间,咱们下篇再见~ |

相关推荐
CANI_PLUS2 分钟前
python 列表-元组-集合-字典
开发语言·python
老秦包你会5 分钟前
QT第六课------QT界面优化------QSS
开发语言·qt
難釋懷6 分钟前
JavaScript基础-history 对象
开发语言·前端·javascript
东方佑8 分钟前
使用 Python 自动处理 Excel 数据缺失值的完整指南
开发语言·python·excel
weixin_4786897612 分钟前
pytorch与其他ai工具
人工智能·pytorch·python
枫林血舞17 分钟前
python笔记之函数
笔记·python
今夜有雨.19 分钟前
HTTP---基础知识
服务器·网络·后端·网络协议·学习·tcp/ip·http
计算机徐师兄29 分钟前
Python Django基于人脸识别的票务管理系统(附源码,文档说明)
python·django·人脸识别·票务系统·票务管理系统·票务管理·人脸识别票务系统
Asthenia041230 分钟前
Seata TCC 模式的空回滚与悬挂问题之解决方案-结合时序分析
后端
看到我,请让我去学习37 分钟前
C语言快速入门-C语言基础知识
c语言·开发语言·c++·vscode