🐍 前端开发 0 基础学 Python 入门指南:文件操作篇
从 JavaScript 的 fs 模块到 Python 的文件操作,让文件读写变得更简单!
📝 一、什么是文件操作?
文件操作是编程中的基础技能,用于读取、写入和处理文件数据。Python 提供了简洁而强大的文件操作 API,类似 Node.js 的 fs 模块,但更加简单易用。
1.1 基本概念
# 最简单的文件操作
f = open('demo.txt') # 打开文件
content = f.read() # 读取内容
f.close() # 关闭文件
核心特点:
- 使用
open()函数打开文件 - 使用文件对象的方法进行读写
- 必须调用
close()关闭文件释放资源
🆚 二、Python vs JavaScript:文件操作对比
2.1 基本读取对比
| 特性 | Node.js (fs) | Python |
|---|---|---|
| 同步读取 | fs.readFileSync() | open().read() |
| 异步读取 | fs.readFile() | 使用异步库(如 aiofiles) |
| 编码指定 | {encoding: 'utf-8'} | encoding='utf-8' |
| 错误处理 | try-catch | try-except |
| 自动关闭 | 无需关闭 | 需要 close() 或使用 with |
// JavaScript - 同步读取文件
const fs = require('fs');
try {
const data = fs.readFileSync('demo.txt', 'utf-8');
console.log(data);
} catch (err) {
console.error('读取失败:', err);
}
# Python - 传统方式读取文件
try:
f = open('demo.txt', encoding='utf-8')
data = f.read()
print(data)
except FileNotFoundError:
print('读取失败: 文件不存在')
finally:
f.close() # 确保文件被关闭
2.2 异步读取对比
// JavaScript - 异步读取
const fs = require('fs').promises;
async function readFile() {
try {
const data = await fs.readFile('demo.txt', 'utf-8');
console.log(data);
} catch (err) {
console.error('读取失败:', err);
}
}
# Python - 使用 with 语句(推荐!)
try:
with open('demo.txt', encoding='utf-8') as f:
data = f.read()
print(data)
# 文件自动关闭,无需手动 close()
except FileNotFoundError:
print('读取失败: 文件不存在')
💡 三、open() 函数详解
3.1 函数签名
open(file, mode='r', buffering=-1, encoding=None, errors=None,
newline=None, closefd=True, opener=None)
3.2 常用参数
| 参数 | 说明 | 默认值 |
|---|---|---|
| file | 文件路径(字符串或 Path 对象) | 必需 |
| mode | 打开模式(读/写/追加等) | 'r' |
| encoding | 文件编码格式 | None |
| buffering | 缓冲策略 | -1 |
| errors | 编码错误处理方式 | None |
3.3 打开模式详解
# ====== 只读模式 ======
'r' # 只读(默认)- 文件必须存在
'rb' # 二进制只读 - 读取图片、视频等
# ====== 写入模式 ======
'w' # 写入 - 文件存在则清空,不存在则创建
'wb' # 二进制写入
'a' # 追加 - 文件存在则在末尾追加,不存在则创建
'ab' # 二进制追加
# ====== 读写模式 ======
'r+' # 读写 - 文件指针在开头,文件必须存在
'w+' # 读写 - 文件存在则清空,不存在则创建
'a+' # 读写 - 文件指针在末尾,不存在则创建
# ====== 示例 ======
# 只读
with open('demo.txt', 'r', encoding='utf-8') as f:
content = f.read()
# 写入(会覆盖原文件!)
with open('output.txt', 'w', encoding='utf-8') as f:
f.write('Hello, Python!')
# 追加
with open('log.txt', 'a', encoding='utf-8') as f:
f.write('新日志\n')
# 二进制读取(图片等)
with open('image.png', 'rb') as f:
image_data = f.read()
🔥 四、with 语句:最佳实践
4.1 为什么使用 with?
传统方式的问题:
# ❌ 不推荐:容易忘记关闭文件
f = open('demo.txt')
content = f.read()
f.close() # 如果前面代码出错,这行不会执行!
# ❌ 更糟的情况
f = open('demo.txt')
content = f.read()
# 忘记 close(),导致资源泄漏
with 语句的优势:
# ✅ 推荐:自动关闭文件
with open('demo.txt', encoding='utf-8') as f:
content = f.read()
# 处理 content
# 离开 with 块后,文件自动关闭,即使发生异常也会关闭
4.2 with 语句的工作原理
# with 语句等价于:
f = open('demo.txt', encoding='utf-8')
try:
content = f.read()
# 处理内容
finally:
f.close() # 无论是否发生异常,都会执行
# 使用 with 更简洁:
with open('demo.txt', encoding='utf-8') as f:
content = f.read()
4.3 同时打开多个文件
# 方式 1:嵌套 with
with open('input.txt', 'r', encoding='utf-8') as f_in:
with open('output.txt', 'w', encoding='utf-8') as f_out:
content = f_in.read()
f_out.write(content.upper())
# 方式 2:一行 with(Python 3.1+,推荐!)
with open('input.txt', 'r', encoding='utf-8') as f_in, \
open('output.txt', 'w', encoding='utf-8') as f_out:
content = f_in.read()
f_out.write(content.upper())
📖 五、文件读取方法
5.1 read() - 读取全部内容
# 一次性读取整个文件(适合小文件)
with open('demo.txt', encoding='utf-8') as f:
content = f.read() # 返回字符串
print(content)
# 读取指定字节数(适合大文件)
with open('demo.txt', encoding='utf-8') as f:
chunk = f.read(100) # 只读取前 100 个字符
print(chunk)
5.2 readline() - 逐行读取
# 读取单行
with open('demo.txt', encoding='utf-8') as f:
line1 = f.readline() # 读取第一行
line2 = f.readline() # 读取第二行
print(line1, line2)
5.3 readlines() - 读取所有行到列表
# 读取所有行到列表
with open('demo.txt', encoding='utf-8') as f:
lines = f.readlines() # 返回列表,每行是一个元素
print(lines) # ['第一行\n', '第二行\n', '第三行\n']
# 常见用法:处理每一行
with open('demo.txt', encoding='utf-8') as f:
lines = f.readlines()
for line in lines:
print(line.strip()) # strip() 去除换行符
5.4 遍历文件对象(最推荐!)
# ✅ 最佳实践:直接遍历文件对象
# 优点:内存友好,适合大文件
with open('demo.txt', encoding='utf-8') as f:
for line in f:
print(line.strip())
# 等价于 readlines(),但不会一次性加载到内存
5.5 读取方法对比
| 方法 | 返回类型 | 适用场景 | 内存占用 |
|---|---|---|---|
read() | 字符串 | 小文件 | 高 |
read(size) | 字符串 | 大文件分块 | 低 |
readline() | 字符串 | 逐行处理 | 低 |
readlines() | 列表 | 小文件 | 高 |
for line | 迭代器 | 推荐! | 最低 |
✍️ 六、文件写入方法
6.1 write() - 写入字符串
# 写入单个字符串
with open('output.txt', 'w', encoding='utf-8') as f:
f.write('Hello, Python!\n')
f.write('第二行内容\n')
# 返回写入的字符数
# ⚠️ 注意:write() 不会自动添加换行符
with open('output.txt', 'w', encoding='utf-8') as f:
f.write('行1')
f.write('行2') # 结果:行1行2(没有换行!)
6.2 writelines() - 写入列表
# 写入字符串列表
lines = ['第一行\n', '第二行\n', '第三行\n']
with open('output.txt', 'w', encoding='utf-8') as f:
f.writelines(lines)
# ⚠️ 注意:writelines() 也不会自动添加换行符
lines = ['行1', '行2', '行3']
with open('output.txt', 'w', encoding='utf-8') as f:
f.writelines(lines) # 结果:行1行2行3(没有换行!)
# ✅ 正确做法:手动添加换行符
with open('output.txt', 'w', encoding='utf-8') as f:
f.writelines([line + '\n' for line in lines])
6.3 print() 直接写入文件
# ✨ 使用 print() 写入文件(自动换行!)
with open('output.txt', 'w', encoding='utf-8') as f:
print('第一行', file=f)
print('第二行', file=f)
print('第三行', file=f)
# 自动添加换行符,非常方便!
🗂️ 七、os 模块:文件和目录操作
7.1 导入 os 模块
import os
# 获取当前工作目录
current_dir = os.getcwd()
print(f'当前目录:{current_dir}')
# 切换工作目录
os.chdir('/Users/wang/Documents')
print(f'切换后:{os.getcwd()}')
7.2 路径操作
import os
# 拼接路径(跨平台兼容)
path = os.path.join('folder', 'subfolder', 'file.txt')
print(path) # macOS/Linux: folder/subfolder/file.txt
# Windows: folder\subfolder\file.txt
# 获取绝对路径
abs_path = os.path.abspath('demo.txt')
print(abs_path) # /Users/wang/Documents/python/demo.txt
# 判断路径是否存在
if os.path.exists('demo.txt'):
print('文件存在')
# 判断是否为文件/目录
print(os.path.isfile('demo.txt')) # True
print(os.path.isdir('demo')) # True
# 获取文件大小(字节)
size = os.path.getsize('demo.txt')
print(f'文件大小:{size} 字节')
# 分割路径
dir_name = os.path.dirname('/Users/wang/demo.txt') # /Users/wang
file_name = os.path.basename('/Users/wang/demo.txt') # demo.txt
name, ext = os.path.splitext('demo.txt') # ('demo', '.txt')
7.3 目录操作
import os
# 创建目录
os.mkdir('new_folder') # 创建单层目录
os.makedirs('a/b/c') # 创建多层目录
# 删除目录
os.rmdir('new_folder') # 删除空目录
os.removedirs('a/b/c') # 删除多层空目录
# 列出目录内容
files = os.listdir('.') # 当前目录所有文件和文件夹
print(files)
# 遍历目录树
for root, dirs, files in os.walk('.'):
print(f'目录:{root}')
print(f'子目录:{dirs}')
print(f'文件:{files}')
7.4 文件操作
import os
# 重命名文件
os.rename('old.txt', 'new.txt')
# 删除文件
os.remove('file.txt')
# 执行系统命令
os.system('ls -l') # macOS/Linux
os.system('dir') # Windows
7.5 环境变量
import os
# 获取环境变量
home = os.environ.get('HOME')
path = os.environ.get('PATH')
# 设置环境变量(仅当前进程有效)
os.environ['MY_VAR'] = 'my_value'
🔄 八、实战:循环文件合并
8.1 合并两个文件
# 方式 1:分别读取再合并
with open('demo.txt', encoding='utf-8') as file1:
file1_data = file1.read()
with open('demo2.txt', encoding='utf-8') as file2:
file2_data = file2.read()
with open('merged.txt', 'w', encoding='utf-8') as merged_file:
merged_file.write(file1_data)
merged_file.write('\n') # 添加换行符分隔
merged_file.write(file2_data)
print('✅ 文件合并完成!')
# 方式 2:使用一行 with(更优雅)
with open('demo.txt', encoding='utf-8') as f1, \
open('demo2.txt', encoding='utf-8') as f2, \
open('merged.txt', 'w', encoding='utf-8') as out:
out.write(f1.read())
out.write('\n')
out.write(f2.read())
8.2 合并多个文件(循环)
# ✨ 批量合并文件
filenames = ['file1.txt', 'file2.txt', 'file3.txt']
with open('merged.txt', 'w', encoding='utf-8') as outfile:
for fname in filenames:
print(f'正在合并:{fname}')
with open(fname, 'r', encoding='utf-8') as infile:
outfile.write(infile.read())
outfile.write('\n') # 文件之间添加换行
print('✅ 所有文件合并完成!')
8.3 高级:带分隔符的合并
import os
filenames = ['file1.txt', 'file2.txt', 'file3.txt']
with open('merged.txt', 'w', encoding='utf-8') as outfile:
for i, fname in enumerate(filenames, 1):
if not os.path.exists(fname):
print(f'⚠️ 文件不存在:{fname}')
continue
# 写入分隔符
outfile.write(f'\n{"="*50}\n')
outfile.write(f'文件 {i}: {fname}\n')
outfile.write(f'{"="*50}\n\n')
# 写入文件内容
with open(fname, 'r', encoding='utf-8') as infile:
outfile.write(infile.read())
print(f'✅ 已合并:{fname}')
print('\n🎉 所有文件合并完成!')
8.4 自动查找并合并
import os
# 自动查找当前目录下所有 .txt 文件并合并
txt_files = [f for f in os.listdir('.') if f.endswith('.txt')]
print(f'找到 {len(txt_files)} 个 txt 文件:')
for f in txt_files:
print(f' - {f}')
with open('all_merged.txt', 'w', encoding='utf-8') as outfile:
for fname in sorted(txt_files): # 按文件名排序
print(f'合并中:{fname}')
outfile.write(f'\n=== {fname} ===\n\n')
with open(fname, 'r', encoding='utf-8') as infile:
outfile.write(infile.read())
outfile.write('\n')
print('✅ 合并完成!')
🎯 九、文件编码处理
9.1 常见编码问题
# ❌ 错误:不指定编码(可能乱码)
with open('demo.txt') as f:
content = f.read()
# ✅ 正确:指定编码
with open('demo.txt', encoding='utf-8') as f:
content = f.read()
9.2 常见编码格式
| 编码 | 说明 | 使用场景 |
|---|---|---|
utf-8 | 万国码(推荐!) | 现代文件默认 |
gbk | 中文编码 | Windows 中文系统 |
gb2312 | 简体中文 | 老版本中文文件 |
ascii | 英文编码 | 纯英文文件 |
latin-1 | 西欧编码 | 部分欧洲语言文件 |
# 处理不同编码的文件
encodings = ['utf-8', 'gbk', 'gb2312', 'latin-1']
for encoding in encodings:
try:
with open('demo.txt', encoding=encoding) as f:
content = f.read()
print(f'✅ 使用 {encoding} 编码读取成功')
break
except UnicodeDecodeError:
print(f'❌ {encoding} 编码失败')
9.3 编码转换
# 将 GBK 文件转换为 UTF-8
with open('gbk_file.txt', 'r', encoding='gbk') as f:
content = f.read()
with open('utf8_file.txt', 'w', encoding='utf-8') as f:
f.write(content)
print('✅ 编码转换完成:GBK → UTF-8')
🛡️ 十、异常处理
10.1 常见文件异常
import os
filename = 'demo.txt'
try:
with open(filename, 'r', encoding='utf-8') as f:
content = f.read()
print(content)
except FileNotFoundError:
print(f'❌ 文件不存在:{filename}')
except PermissionError:
print(f'❌ 没有权限访问:{filename}')
except UnicodeDecodeError:
print(f'❌ 编码错误,请尝试其他编码格式')
except IOError as e:
print(f'❌ IO 错误:{e}')
except Exception as e:
print(f'❌ 未知错误:{e}')
10.2 安全的文件操作
def safe_read_file(filename, encoding='utf-8'):
"""安全地读取文件"""
# 检查文件是否存在
if not os.path.exists(filename):
print(f'❌ 文件不存在:{filename}')
return None
# 检查是否为文件
if not os.path.isfile(filename):
print(f'❌ 不是文件:{filename}')
return None
# 检查文件大小(避免读取超大文件)
size = os.path.getsize(filename)
if size > 10 * 1024 * 1024: # 10MB
print(f'⚠️ 文件太大:{size / 1024 / 1024:.2f} MB')
return None
# 读取文件
try:
with open(filename, 'r', encoding=encoding) as f:
return f.read()
except Exception as e:
print(f'❌ 读取失败:{e}')
return None
# 使用
content = safe_read_file('demo.txt')
if content:
print(content)
📚 十一、总结
核心要点
- 使用 with 语句:自动管理文件关闭,避免资源泄漏
- 指定编码格式:优先使用
encoding='utf-8' - 选择合适的读取方法:
- 小文件:
read() - 大文件:
for line in file(推荐) - 需要列表:
readlines()
- 小文件:
- os 模块:处理路径、目录、文件信息
- 异常处理:使用 try-except 捕获文件操作异常
Python vs JavaScript 文件操作
| 特性 | Node.js | Python |
|---|---|---|
| 打开文件 | fs.readFileSync() | open() |
| 自动关闭 | 不需要 | 需要 with 或 close() |
| 同步读取 | readFileSync() | read() |
| 异步读取 | readFile() / promises | aiofiles(需要安装) |
| 路径操作 | path 模块 | os.path 模块 |
| 目录操作 | fs.mkdir() 等 | os.mkdir() 等 |
| 编码指定 | {encoding: 'utf-8'} | encoding='utf-8' |
最佳实践
- ✅ 永远使用 with 语句打开文件
- ✅ 明确指定 encoding参数
- ✅ 使用 os.path.join() 拼接路径(跨平台兼容)
- ✅ 大文件使用迭代器(
for line in file) - ✅ 添加异常处理,提高程序健壮性
- ❌ 避免忘记关闭文件
- ❌ 避免一次性读取超大文件到内存
- ❌ 避免硬编码路径分隔符(用
os.path.join())
常用代码模板
# 📖 读取文件模板
with open('file.txt', 'r', encoding='utf-8') as f:
content = f.read()
# ✍️ 写入文件模板
with open('file.txt', 'w', encoding='utf-8') as f:
f.write('content')
# 🔄 逐行处理模板(推荐)
with open('file.txt', encoding='utf-8') as f:
for line in f:
process(line.strip())
# 🗂️ 路径操作模板
import os
path = os.path.join('folder', 'file.txt')
if os.path.exists(path):
with open(path, encoding='utf-8') as f:
content = f.read()
# 🔗 文件合并模板
files = ['f1.txt', 'f2.txt', 'f3.txt']
with open('merged.txt', 'w', encoding='utf-8') as out:
for fname in files:
with open(fname, encoding='utf-8') as f:
out.write(f.read())
out.write('\n')
本文适合前端开发者快速掌握 Python 文件操作,通过对比 Node.js 的 fs 模块来理解 Python 的文件处理机制。记住:永远使用 with 语句,明确指定编码! 🚀