文件处理是编程核心能力之一,可实现程序与文件系统交互,完成文件读取、写入、编辑及删除操作。在运维与企业业务场景中,文件处理广泛应用于日志运维、数据备份、文件规整清理等实际工作。
一、文件基础操作
在 Python 中,文件操作通过内置函数 open() 实现。可以使用不同模式打开文件,常用模式如下:
- '
r':只读模式(默认) - '
w':写入模式(会覆盖原有内容) - '
a':追加模式(在文件末尾添加内容)
文件操作完成后必须关闭文件以释放系统资源。Python 提供了 file.close() 方法手动关闭文件,更推荐使用 with 语句,它会在代码块结束后自动关闭文件,更安全、更简洁。
案例:
file文件夹下有文件example.txt,内容如下:
test file.
welcome to learn python.
代码:
file = open('file/example.txt', 'r')
text = file.read()
file.close()
print(text)
输出:
test file.
welcome to learn python.
代码讲解
open('example.txt','r'):以只读模式打开指定文件file.read():一次性读取文件全部内容file.close():手动关闭文件,必须执行,否则会占用资源
推荐写法(with 语句)
with open('file/example.txt', 'r') as file:
text = file.read()
print(text)
输出:
test file.
welcome to learn python.
with 语句作用
with 是 Python 的上下文管理器 ,无论代码是否报错,都会在代码块结束后自动关闭文件,安全且简洁。
as file
as:把打开后的文件对象 赋值给变量filefile:你可以自定义名称,用来操作文件- 在
with代码块内可以正常读写 - 代码块结束后,文件自动关闭
二、文件的读取与写入
Python 支持三种主流文件读取方式:读取全部内容、逐行读取、读取所有行至列表。
file.read():读取整个文件全部内容for line in file:逐行遍历读取文件内容file.readlines():读取所有行,存入列表
1. 读取整个文件 read ()
一次性加载文件全部内容,适合小文件。
with open('file/example.txt', 'r') as file:
text = file.read()
print(text)
代码解析
with open('file/example.txt','r') as file:以只读模式打开文件,自动关闭资源file.read():读取文件全部内容,赋值给变量textprint(text):输出完整的文件内容
2. 逐行读取文件 for 循环
逐行迭代读取,节省内存,适合大文件、日志文件。
with open('file/example.txt', 'r') as file:
print("file text:")
for line in file:
print(line, end='')
输出:
file text:
test file.
welcome to learn python.
代码解析
for line in file:循环遍历文件的每一行数据- end='' 作用:
- 默认
print()会自带换行符,而文件每行本身自带换行,直接打印会出现多余空行 end=''取消 print 默认换行,完全保留文件原始排版格式
- 默认
3. 读取所有行到列表 readlines ()
将文件每一行作为列表元素存储,方便对单行数据单独操作。
with open('file/example.txt', 'r') as file:
lines = file.readlines()
print(lines)
输出:
'test file.\\n', 'welcome to learn python.'
file.readlines():读取文件所有行,返回一个行数据列表
三种读取方式区别与适用场景
1. read () 读取全部内容
- 优点:代码简洁,直接获取完整文本,方便整体处理
- 缺点:一次性加载全部内容,大文件会占用大量内存
- 适用场景:文件体积小、需要整体分析、整体修改文件内容
2. for line in file:逐行读取文件内容
- 优点 :
- 内存友好,适合处理大文件;仅当前行驻留内存,避免一次性加载全量数据。
- 文件对象为可迭代器,语法简洁,天然支持流式处理。
- 缺点 :
- 无法随机访问(如跳转到第100行),只能顺序遍历。
- 若需多次遍历文件,需重新打开或使用
file.seek(0)重置指针。
- 适用场景 :
- 文件体积大(如日志、CSV、大数据集),内存受限时。
- 需对每行进行独立处理(如清洗、过滤、统计、写入新文件)。
- 实时流处理或管道式数据处理(如配合生成器、
map/filter等)。
3. file.readlines():读取全部行并返回列表
- 优点 :
- 支持随机访问(通过索引
lines[i]快速获取任意行)。 - 可多次遍历、重复使用,便于复杂分析(如交叉比对、排序、分组)。
- 代码逻辑清晰,适合小规模数据的批量操作。
- 支持随机访问(通过索引
- 缺点 :
- 一次性将整个文件载入内存,对大文件易引发
MemoryError。 - 占用内存约为文件大小的 1.5--2 倍(因字符串对象开销及列表结构)。
- 一次性将整个文件载入内存,对大文件易引发
- 适用场景 :
- 文件较小(如 < 100 MB,具体取决于可用内存)。
- 需要频繁访问不同行(如查找特定关键词所在行号、构建索引)。
- 数据需整体预处理后再分析(如解析配置文件、小型JSON/CSV转换)。
写入文件基础方法
文件写入分为覆盖写入和追加写入,常用两个方法:
file.write():写入单行内容,配合w模式会覆盖原有内容file.writelines():批量写入多行内容(支持列表、字符串)
覆盖写入文件(w 模式)
使用 w 写入模式 打开文件,会直接清空文件原有内容,写入新数据。
with open('file/example.txt', 'w') as file:
file.write('hello world\n')
with open('file/example.txt', 'r') as file:
text = file.read()
print(text)
输出:hello world
代码解析
-
with open('example.txt', 'w') as file:以写入模式打开文件,覆盖原有全部内容,文件不存在则自动创建。 -
file.write("Hello, World!\n"):向文件中写入指定字符串,\n代表换行。
追加写入文件(a 模式)
with open('file/example.txt', 'a') as file:
file.write("666666.\n") # 追加新行到文件末尾
重新读取文件,查看追加后的效果
with open('file/example.txt', 'r') as file:
text = file.read()
print(text)
输出:
hello world
代码解析
-
with open('example.txt', 'a') as file: 以追加模式打开文件,保留原内容,在末尾续写。 -
**
file.write():**在文件末尾追加一行新内容。
一次性写入多行内容(writelines)
如果需要批量写入多行数据,可以将内容存入列表,使用 writelines() 一次性写入。
lines = ["line1","line2","line3"]
with open('file/example.txt', 'w') as file:
file.writelines(line + "\n" for line in lines)
重新读取文件,查看追加后的效果
with open('file/example.txt', 'r') as file:
text = file.read()
print(text)
输出:
line1
line2
line3
代码解析
-
将所有需要写入的内容存入列表,每行末尾需要手动添加
\n换行符。 -
file.writelines(lines):遍历列表,将所有元素批量写入文件。
写入模式核心区别总结
-
w 模式:覆盖写入,清空旧内容、写入新内容
-
a 模式:追加写入,保留旧内容、末尾加新内容
-
write():写入单个字符串
-
writelines():批量写入列表多行字符串
三、文件和目录管理
理论
Python 的 os 和 shutil 模块提供了文件和目录的管理功能,包括创建、删除、重命名文件和目录等。
案例
import os
with open('file/old_name.txt', 'w') as file:
file.write('renamed\n')
os.rename('file/old_name.txt', 'file/new_name.txt')
if os.path.exists('file/new_name.txt'):
print("File renamed successfully.")
else:
print("File not found.")
输出:
File renamed successfully.
删除文件:
import os
with open('file/delete.txt', 'w') as file:
file.write('delete\n')
os.remove('file/delete.txt')
if os.path.exists('file/delete.txt'):
print("File not found.")
else:
print("File deleted successfully.")
输出:
File deleted successfully.
删除目录
import os
os.makedirs('file/my_directory')
os.rmdir('file/my_directory')
if not os.path.exists('file/my_directory'):
print("Directory deleted successfully.")
else:
print("Directory not found.")
复制文件
import os
import shutil
with open('file/source_file.txt', 'w') as file:
file.write('copy\n')
shutil.copy('file/source_file.txt', 'file/destination_file.txt')
if os.path.exists('file/destination_file.txt'):
print("File copied successfully.")
else:
print("File not found.")
移动文件
import os
import shutil
with open('file/move.txt', 'w') as file:
file.write('move\n')
shutil.move('file/move.txt', 'file/moved.txt')
if os.path.exists('file/moved.txt'):
print("File moved successfully.")
else:
print("File not found.")
处理大文件
处理大文件时,直接将整个文件读入内存可能会导致内存不足或程序变得非常慢。因此,逐块读取文件内容是一种更有效的方式,这样可以逐步处理文件内容,而不是一次性加载整个文件。这种方法特别适合处理大型日志文件、大型数据文件等。
逐块读取的主要优点包括:
节省内存:只需将文件的一部分加载到内存中,而不是整个文件。
提高性能:可以立即开始处理文件的一部分数据,而不是等待整个文件加载完成。
import os
chunk_size = 1024
with open('file/source_file.txt', 'w') as source_file:
source_file.write('A' * chunk_size * 10)
with open('file/source_file.txt', 'r') as source_file:
while True:
chunk = source_file.read(chunk_size)
if not chunk:
break
print(chunk[:100])
代码解释:
1. 创建模拟大文件
- 打开/创建文件 :使用
with open('large_file.txt', 'w') as file:以文本写入模式打开文件。若文件不存在则自动创建,with语句确保操作完成后文件被安全关闭。 - 写入测试数据 :通过
file.write("A" * 1024 * 1024)向文件中写入 1 MB(1,048,576 个字符)的连续字符"A",用于模拟一个需要分块处理的大文件。
2. 分块读取核心流程
- 打开待读文件 :使用
with open('large_file.txt', 'r') as file:以文本只读模式打开目标文件。 - 构建读取循环 :采用
while True:无限循环持续读取数据块,这是 Python 中处理流式数据的标准范式。 - 按块读取数据 :在循环体内执行
chunk = file.read(chunk_size),每次从当前文件指针位置读取固定大小(本例为 1 KB)的数据。 - 检测文件末尾 :通过
if not chunk: break判断读取结果。当read()到达文件末尾时返回空字符串'',其布尔值为False,触发break安全退出循环。 - 采样打印预览 :执行
print(chunk[:100])仅输出当前数据块的前 100 个字符。此举旨在验证数据内容的正确性,同时避免将大量数据直接输出到控制台导致性能卡顿或信息过载。
3. ⚠️ 关键技术注解
文本模式 vs 二进制模式的区别
当前代码使用
'r'(文本模式),此时file.read(chunk_size)读取的单位是 字符数 而非字节数。对于纯 ASCII 字符(如"A"),1 字符 = 1 字节,两者等价;但若文件包含 UTF-8 编码的中文等多字节字符,1024 个字符实际占用的字节数会远超 1024 字节。若需严格按字节分块(如处理图片、视频或网络流),应改用'rb'二进制模式。
实际案例:
你需要备份某个目录中的所有文件到另一个备份目录。每次备份时,创建一个新的备份文件夹,以便将文件按时间戳命名。
import os
import shutil
from datetime import datetime
src_dir = 'file/source'
dest_dir = 'file/backup'
if not os.path.exists(src_dir):
os.makedirs(src_dir)
os.makedirs(os.path.join(src_dir, 'subdir1'), exist_ok=True)
os.makedirs(os.path.join(src_dir, 'subdir2'), exist_ok=True)
with open(os.path.join(src_dir, 'file1.txt'), 'w') as f:
f.write('This is file 1.')
with open(os.path.join(src_dir, 'subdir1', 'file2.txt'), 'w') as f:
f.write('This is file 2.')
with open(os.path.join(src_dir, 'subdir2', 'file3.txt'), 'w') as f:
f.write('This is file 3.')
if not os.path.exists(dest_dir):
os.makedirs(dest_dir)
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
backup_dir = os.path.join(dest_dir, f'backup_{timestamp}')
os.makedirs(backup_dir)
for item in os.listdir(src_dir):
s = os.path.join(src_dir, item)
d = os.path.join(backup_dir, item)
if os.path.isdir(s):
shutil.copytree(s, d,dirs_exist_ok=True,copy_function=shutil.copy2)
else:
shutil.copy2(s, d)
print(f'Backup of {src_dir} created in {backup_dir}')
代码解释:
if os.path.isdir(s):
意思:判断 s 是不是文件夹
s= 源路径(比如file/source/subdir1)- 如果是文件夹 → 执行
copytree - 如果是文件 → 执行
copy2
shutil.copytree(...)
作用:复制 整个文件夹 + 里面所有内容 (文件 + 子文件夹 + 全部内容,一键复制)
里面的参数:
s → 源文件夹(从哪复制)
d → 目标文件夹(复制到哪)
dirs_exist_ok=True
意思:如果目标文件夹已经存在,不报错,直接覆盖 / 合并
- 默认是
False,如果文件夹已存在会直接崩溃 - 你写
=True就是告诉程序: "文件夹存在没关系,我允许覆盖"
copy_function=shutil.copy2
意思:复制文件时,用 copy2 这个方法
shutil.copy2(s, d)
作用:复制 单个文件
copy2 比普通复制更强:
- 不仅复制内容
- 还保留文件的:创建时间、修改时间、权限
清除过期日志文件
log_path = 'file/logs'
if not os.path.exists(log_path):
os.makedirs(log_path)
days_list = [15, 30, 45, 60]
for days in days_list:
file_name = f"log_{days}days.txt"
file_path = os.path.join(log_path, file_name)
with open(file_path, 'w') as file:
file.write(f"This is the log file for {days} days.\n")
past_time = datetime.now() - timedelta(days=days)
past_timestamp = past_time.timestamp()
os.utime(file_path, (past_timestamp, past_timestamp))
print(f"Log files created in {log_path}")
days = 30
cutoff = datetime.now() - timedelta(days=days)
for file_name in os.listdir(log_path):
file_path = os.path.join(log_path, file_name)
if os.path.isfile(file_path):
file_time = os.path.getmtime(file_path)
file_datetime = datetime.fromtimestamp(file_time)
if file_datetime < cutoff:
os.remove(file_path)
删除了30天以上的日志
批量重命名文件
"""
file = open('file/example.txt', 'r')
text = file.read()
file.close()
print(text)
"""
"""
with open('file/example.txt', 'r') as file:
text = file.read()
print(text)
"""
"""
with open('file/example.txt', 'r') as file:
print("file text:")
for line in file:
print(line, end='')
"""
"""
with open('file/example.txt', 'r') as file:
lines = file.readlines()
print(lines)
with open('file/example.txt', 'r') as file:
lines = file.readlines() # 将文件的每一行读入列表
print("File Content:")
for line in lines:
print(line, end='')
"""
"""
with open('file/example.txt', 'w') as file:
file.write('hello world\n')
with open('file/example.txt', 'r') as file:
text = file.read()
print(text)
追加数据到文件末尾
with open('file/example.txt', 'a') as file:
file.write("666666.\n") # 追加新行到文件末尾
重新读取文件,查看追加后的效果
with open('file/example.txt', 'r') as file:
text = file.read()
print(text)
lines = ["line1","line2","line3"]
with open('file/example.txt', 'w') as file:
file.writelines(line + "\n" for line in lines)
重新读取文件,查看追加后的效果
with open('file/example.txt', 'r') as file:
text = file.read()
print(text)
"""
import os
import shutil
from datetime import datetime, timedelta
"""
src_dir = 'file/source'
dest_dir = 'file/backup'
if not os.path.exists(src_dir):
os.makedirs(src_dir)
os.makedirs(os.path.join(src_dir, 'subdir1'), exist_ok=True)
os.makedirs(os.path.join(src_dir, 'subdir2'), exist_ok=True)
with open(os.path.join(src_dir, 'file1.txt'), 'w') as f:
f.write('This is file 1.')
with open(os.path.join(src_dir, 'subdir1', 'file2.txt'), 'w') as f:
f.write('This is file 2.')
with open(os.path.join(src_dir, 'subdir2', 'file3.txt'), 'w') as f:
f.write('This is file 3.')
if not os.path.exists(dest_dir):
os.makedirs(dest_dir)
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
backup_dir = os.path.join(dest_dir, f'backup_{timestamp}')
os.makedirs(backup_dir)
for item in os.listdir(src_dir):
s = os.path.join(src_dir, item)
d = os.path.join(backup_dir, item)
if os.path.isdir(s):
shutil.copytree(s, d,dirs_exist_ok=True,copy_function=shutil.copy2)
else:
shutil.copy2(s, d)
print(f'Backup of {src_dir} created in {backup_dir}')
"""
"""
log_path = 'file/logs'
if not os.path.exists(log_path):
os.makedirs(log_path)
days_list = [15, 30, 45, 60]
for days in days_list:
file_name = f"log_{days}days.txt"
file_path = os.path.join(log_path, file_name)
with open(file_path, 'w') as file:
file.write(f"This is the log file for {days} days.\n")
past_time = datetime.now() - timedelta(days=days)
past_timestamp = past_time.timestamp()
os.utime(file_path, (past_timestamp, past_timestamp))
print(f"Log files created in {log_path}")
days = 30
cutoff = datetime.now() - timedelta(days=days)
for file_name in os.listdir(log_path):
file_path = os.path.join(log_path, file_name)
if os.path.isfile(file_path):
file_time = os.path.getmtime(file_path)
file_datetime = datetime.fromtimestamp(file_time)
if file_datetime < cutoff:
os.remove(file_path)
"""
log_path = 'file/logs'
old_ext= '.txt'
new_ext = '.log'
if not os.path.exists(log_path):
os.makedirs(log_path)
days_list = [15, 30, 45, 60]
for days in days_list:
file_name = f"log_{days}days.txt"
file_path = os.path.join(log_path, file_name)
with open(file_path, 'w') as file:
file.write(f"This is the log file for {days} days.\n")
past_time = datetime.now() - timedelta(days=days)
past_timestamp = past_time.timestamp()
os.utime(file_path, (past_timestamp, past_timestamp))
print(f"Log files created in {log_path}")
for file_name in os.listdir(log_path):
if file_name.endswith(old_ext):
new_file_name = os.path.splitext(file_name)[0] + new_ext
new_file_path = os.path.join(log_path, new_file_name)
old_file_path = os.path.join(log_path, file_name)
os.rename(old_file_path, new_file_path)