Python文件操作
在 Python 中,文件操作是非常常见的任务。Python 提供了内置的函数来处理文件的读写操作。
文件的类型
- 文本文件:包含可读的字符(如
.txt
、.csv
)。一般使用 UTF-8 编码,可以使用文本编辑器查看; - 二进制文件:包含非文本数据(如图像、音频、视频文件,后缀如
.jpg
、.png
、.mp3
)。以原始字节格式存储。需要使用专用软件查看;
文件操作的过程
打开文件;
读写文件;
读文件:将文件内容读入内存;
写文件:将内存内容写入文件;
关闭文件;
操作方法
打开文件
使用 open()
函数打开文件
open
函数负责打开文件,并且返回文件对象
- 第一个参数是文件名(文件名区分大小写),第二个参数是打开方式;
- 如果文件存在返回文件操作对象;
- 如果文件不存在抛出异常
f = open("文件名", "访问方式")
文件路径
绝对路径:
从根路径开始描述文件的位置,例如:F:\技术文件\课件-笔记\课件修订\Python\01.Python基础语法
具有唯一性,不会出错,不管写在哪里都可以准确的找到文件的位置
相对路径:
相对当前位置进行文件定位,容易出错,需要对路径比较熟悉
以不同模式打开
访问方式 | 说明 |
---|---|
r | 以只读方式打开文件。文件的指针将会放在文件的开头,这是默认模式。如果文件不存在,抛出异常 |
w | 以只写方式打开文件。如果文件存在会被覆盖。如果文件不存在,创建新文件 |
a | 以追加方式打开文件。如果该文件已存在,文件指针将会放在文件的结尾。如果文件不存在,创建新文件进行写入 |
r+ | 以读写方式打开文件。文件的指针将会放在文件的开头。如果文件不存在,抛出异常 |
w+ | 以读写方式打开文件。如果文件存在会被覆盖。如果文件不存在,创建新文件 |
a+ | 以读写方式打开文件。如果该文件已存在,文件指针将会放在文件的结尾。如果文件不存在,创建新文件进行写入 |
以bytes类型操作的读写,写读,写读模式
r+b | 读写【可读,可写】 |
---|---|
w+b | 写读【可写,可读】 |
a+b | 写读【可写,可读】 |
对于非文本文件,我们只能使用b模式,"b"表示以字节的方式操作(而所有文件也都是以字节的形式存储的,使用这种模式无需考虑文本文件的字符编码、图片文件的jgp格式、视频文件的avi格式)
注:以b方式打开时,读取到的内容是字节类型,写入时也需要提供字节类型,不能指定编码文件编码
f=open(...)是由操作系统打开文件,那么如果我们没有为open指定编码,那么打开文件的默认编码很明显是操作系统说了算了,操作系统会用自己的默认编码去打开文件,在windows下是gbk,在linux下是utf-8。
f=open('example.txt','r',encoding='utf-8')
读取文件
read(size)
:读取指定大小的内容,如果没有指定,读取全部内容。readline()
:读取一行。readlines()
:读取所有行并返回一个列表。
示例:
file = open('example.txt', 'r')
content = file.read() # 读取全部内容
line = file.readline() # 读取一行
lines = file.readlines() # 读取所有行
print(content)
print('-----------')
print(line)
print('-----------')
print(lines)
# 思考?
# 为什么后面两个print读取不到东西呢?
文件指针 seek
有时候我们想要改变文件指针(光标)的位置,就需要用到seek方法来操作指针
语法:
file.seek(offset, whence)
offset
:要移动的字节数。whence
(可选):指定偏移量的基准位置。可以取以下值:
0
:从文件开头开始计算(默认值)。1
:从当前位置开始计算。2
:从文件末尾开始计算
示例:
file = open('example.txt', 'r')
content = file.read() # 读取全部内容
file.seek(0) # 把光标移到到文件的开头
line = file.readline() # 读取一行
file.seek(0) # 再次把光标移动到文件的开头
lines = file.readlines() # 读取所有行
print(content)
print('-----------')
print(line)
print('-----------')
print(lines)
按行读取文件内容
- read方法默认会把文件的所有内容一次性读取到内存
- readline方法可以一次读取一行内容
# 方式一、通过循环按行读取文件所有内容
file1 = open("example.txt")
i = 1
while True:
text1 = file1.readline().strip()
if text1:
print("这是第%s行内容" % i)
i += 1
print(text1)
else:
break
file1.close()
file2 = open("example.txt")
# 通过for遍历按行读取文件所有内容
for i in file2.readlines():
print(i.strip())
file2.close()
写入内容
可以对文件对象调用write方法实现写入内容
语法:
file.write()
示例:日记记录
# 日记程序
# 以追加模式打开日记文件
file = open('diary.txt', 'a',encoding='utf-8')
# 获取用户输入的日记内容
content = input("请输入今天的日记:")
# 将日记内容写入文件
file.write(content + "\n")
print("日记已保存!")
# 关闭文件
file.close()
关闭文件
语法:
file.close()
使用 close()
方法关闭文件,释放系统资源,防止文件被一直占用
with结构
使用 with
语句可以自动管理文件的打开和关闭,避免忘记关闭文件的情况。
with open('example.txt', 'r') as file: # 获取file文件对象
content = file.read()
案例:简单的备份程序
将一个文本文件的内容复制到另一个文件,用于简单的备份。
# 简单备份小程序
source = 'a.txt'
destination = 'b.txt'
with open(source, 'r',encoding='utf-8') as src:
content = src.read()
with open(destination, 'w',encoding='utf-8') as dest:
dest.write(content)
print(f"备份成功!'{source}' 的内容已复制到 '{destination}'")
其他文件操作
除了上述讲到的常用操作之外,还有很多其他的操作。这里我们列出在这,就不一一带着大家去看了。用到的时候可以回头来查一下就行
class CustomFile:
def __init__(self, *args, **kwargs):
"""初始化文件对象."""
pass
@staticmethod
def __new__(*args, **kwargs):
"""创建并返回一个新的对象."""
pass
def close(self, *args, **kwargs):
"""关闭文件."""
pass
def fileno(self, *args, **kwargs):
"""返回文件描述符."""
pass
def flush(self, *args, **kwargs):
"""刷新文件内部缓冲区."""
pass
def isatty(self, *args, **kwargs):
"""判断文件是否是一个终端设备."""
pass
def read(self, *args, **kwargs):
"""读取指定字节的数据."""
pass
def readable(self, *args, **kwargs):
"""检查文件是否可读."""
pass
def readline(self, *args, **kwargs):
"""仅读取一行数据."""
pass
def seek(self, *args, **kwargs):
"""移动文件指针到指定位置."""
pass
def seekable(self, *args, **kwargs):
"""检查指针是否可操作."""
pass
def tell(self, *args, **kwargs):
"""获取当前指针位置."""
pass
def truncate(self, *args, **kwargs):
"""截断文件,仅保留指定之前的数据."""
pass
def writable(self, *args, **kwargs):
"""检查文件是否可写."""
pass
def write(self, *args, **kwargs):
"""写入内容到文件."""
pass
def __next__(self, *args, **kwargs):
"""实现迭代器的 next() 方法."""
pass
def __repr__(self, *args, **kwargs):
"""返回文件对象的字符串表示."""
pass
def __getstate__(self, *args, **kwargs):
"""自定义对象的序列化状态."""
pass
解释
__init__
: 初始化文件对象的方法。通常在这里设置文件的基本属性。__new__
: 静态方法,用于创建新的对象实例。close
: 关闭文件,释放系统资源。fileno
: 返回文件描述符,通常用于与底层操作系统交互。flush
: 刷新文件的内部缓冲区,将未写入的数据写入文件。isatty
: 判断文件是否是一个终端设备(tty),用于检查文件是否连接到一个用户界面。read
: 读取指定字节的数据,可以用来读取文件内容。readable
: 检查文件对象是否可读。readline
: 读取文件中的一行数据,常用于逐行读取文件内容。seek
: 移动文件指针到指定位置,允许在文件中随机访问。seekable
: 检查文件指针是否可操作,确定文件是否支持随机访问。tell
: 返回当前文件指针的位置。truncate
: 截断文件,只保留指定位置之前的数据。writable
: 检查文件对象是否可写。write
: 向文件写入内容。__next__
: 实现迭代器的next()
方法,用于支持迭代访问文件的内容。__repr__
: 返回文件对象的字符串表示,通常用于调试。__getstate__
: 自定义对象的序列化状态,用于存储和恢复对象的状态。
案例练习
案例一 文件修改
文件的数据是存放于硬盘上的,因而只存在覆盖、不存在修改这么一说,我们平时看到的修改文件,都是模拟出来的效果,具体的说有两种实现方式:
方式一:将硬盘存放的该文件的内容全部加载到内存,在内存中是可以修改的,修改完毕后,再由内存覆盖到硬盘(word,vim,nodpad++等编辑器)
import os
with open('a.txt') as read_f,open('a.txt.new','w') as write_f:
data = read_f.read()
data = data.replace('Hello','nihao')
write_f.write(data)
os.remove('a.txt')
os.rename('a.txt.new','a.txt')
方式二:将硬盘存放的该文件的内容一行一行地读入内存,修改完毕就写入新文件,最后用新文件覆盖源文件
import os
with open('a.txt') as read_f,open('a.txt.new','w') as write_f:
for line in read_f:
line = line.replace('nihao','Hello')
write_f.write(line)
os.remove('a.txt')
os.rename('a.txt.new','a.txt')
案例二 商品信息管理与总价计算
背景
在日常的商业管理中,商品的管理和销售记录是非常重要的。我们需要一种方式来处理商品信息,包括商品名称、价格和数量。通过这些信息,我们可以计算出总价,帮助商家了解销售情况。
目标
本案例旨在通过 Python 读取存储在文本文件中的商品信息,并将其转换为易于操作的数据结构。具体目标包括:
- 从文件
a.txt
中读取每一行的商品信息。 - 将读取的信息构建为包含字典的列表,每个字典表示一个商品,包含名称、价格和数量。
- 计算所有商品的总价,并输出结果。
文件内容示例
a.txt
文件的内容如下:
apple 10 3
tesla 100000 1
mac 3000 2
lenovo 30000 3
chicken 10 3
每行代表一个商品,格式为:商品名称 价格 数量
。
代码示例
# 初始化商品列表
products = []
# 读取文件并构建商品列表
with open('a.txt', 'r', encoding='utf-8') as file:
for line in file:
# 去除行首尾空白并分割
parts = line.strip().split()
if len(parts) == 3: # 确保有三个部分
product = {
'name': parts[0],
'price': int(parts[1]), # 转换为整数
'amount': int(parts[2]) # 转换为整数
}
products.append(product)
# 输出商品列表
print("商品列表", products)
total_price = 0
# 计算总价
for i in products:
total_price += i['price'] * i['amount']
# 输出总价
print("总价:", total_price)
# Output:
[{'name': 'apple', 'price': 10, 'amount': 3}, {'name': 'tesla', 'price': 100000, 'amount': 1}, {'name': 'mac', 'price': 3000, 'amount': 2}, {'name': 'lenovo', 'price': 30000, 'amount': 3}, {'name': 'chicken', 'price': 10, 'amount': 3}]
总价: 196060
案例三 基于文件的账户验证
将用户信息存放在文件user.txt中,并且格式如下
张三|123456
代码示例:
db = {}
with open("sql.txt","r", encoding="utf-8") as f:
data = f.readlines()
print(data)
for i in data:
ret = i.strip().split("|")
# ret = ["张三", "123"]
print(ret)
db[ret[0]] = ret[1]
# db["张三"] = "123"
print(db)
while True:
username = input("请输入用户名:")
if username in db:
password = input("请输入密码:")
if password ==db[username]:
print("登录成功")
else:
print("密码错误登录失败")
else:
print("用户名不存在")
课后作业
1. 完成上述几个案例
2. 扩展案例三 基于文件的账户验证。为其增加注册功能并且让整个代码更加合理
3. 尝试一下实现密码错误3次封号的功能