别再用open硬写了,Python文件读写这5个骚操作让你瞬间变大佬

36 阅读5分钟

你是不是也遇到过这种情况:

f = open('data.txt', 'r')
data = f.read()
print(data)

然后程序报错:

ValueError: I/O operation on closed file.

你一脸懵逼:文件明明刚打开,怎么就关闭了?

经过一番折腾,你才发现需要在finally里加f.close(),或者用with语句。但即便如此,还是各种编码问题、路径问题、性能问题接踵而至。

今天咱们就来彻底搞懂Python文件读写,让你从小白瞬间变大牛。

1. 用with语句,别问我为什么

还在用这种方式写文件操作?

# ❌ 危险操作,容易忘记关闭文件
f = open('test.txt', 'w')
f.write('Hello World')
# 如果这里抛异常,文件就永远无法关闭了!
f.close()

或者这种?

# ❌ 看似安全,实则繁琐
f = open('test.txt', 'w')
try:
    f.write('Hello World')
finally:
    f.close()

正确的姿势是这样的:

# ✅ 优雅、安全、自动关闭
with open('test.txt', 'w', encoding='utf-8') as f:
    f.write('Hello World')
# 退出with块自动关闭文件,即使出现异常也没问题

with语句就像是给你请了个贴身保镖,无论发生什么,都会确保文件被正确关闭。这不比你手动管理强100倍?

2. 编码问题?一招制敌

# ❌ 编码噩梦的开始
with open('chinese.txt', 'r') as f:
    content = f.read()
# 运行结果:UnicodeDecodeError: 'gbk' codec can't decode byte 0xff...

看到这个错误,你是不是想砸电脑?

记住这个黄金法则:

# ✅ 永远指定编码
with open('chinese.txt', 'r', encoding='utf-8') as f:
    content = f.read()

为什么是utf-8?

  • 它是互联网的通用语言
  • 支持全世界所有字符
  • 基本不会出现乱码问题

特殊情况处理:

# 读Windows记事本保存的文件
with open('notepad.txt', 'r', encoding='gbk') as f:
    content = f.read()

# 处理编码不确定的文件
def read_file_safe(filename):
    encodings = ['utf-8', 'gbk', 'latin1']
    for encoding in encodings:
        try:
            with open(filename, 'r', encoding=encoding) as f:
                return f.read()
        except UnicodeDecodeError:
            continue
    raise ValueError("无法识别文件编码")

3. 一次性读取 vs 逐行读取,性能差10倍

# ❌ 内存杀手,文件大了直接爆内存
with open('big_file.txt', 'r') as f:
    content = f.read()  # 100MB文件 = 100MB内存占用
    lines = content.split('\n')

聪明人的写法:

# ✅ 内存友好,无论文件多大都只占用一行内存
with open('big_file.txt', 'r') as f:
    for line in f:  # 逐行读取,内存占用几乎为0
        print(line.strip())

具体场景选择:

# 小文件(<10MB),直接读取,简单粗暴
with open('small.txt', 'r') as f:
    content = f.read()

# 中等文件(10MB-100MB),逐行处理
with open('medium.txt', 'r') as f:
    for line in f:
        process_line(line)

# 大文件(>100MB),批量处理
def process_large_file(filename, batch_size=1000):
    with open(filename, 'r') as f:
        batch = []
        for line in f:
            batch.append(line.strip())
            if len(batch) >= batch_size:
                process_batch(batch)
                batch = []
        if batch:  # 处理最后一批
            process_batch(batch)

4. 路径处理的优雅姿势

# ❌ Windows用户噩梦
with open('C:\\Users\\张三\\Documents\\data.txt', 'r') as f:
    content = f.read()

# ❌ 拼接路径容易出错
import os
path = 'data' + '\\' + 'subdir' + '\\' + 'file.txt'

用pathlib,让路径处理变成艺术:

# ✅ 跨平台,自动处理分隔符
from pathlib import Path

# 基础用法
path = Path('data') / 'subdir' / 'file.txt'
with open(path, 'r') as f:
    content = f.read()

# 高级操作
data_dir = Path.home() / 'documents' / 'data'
data_dir.mkdir(exist_ok=True)  # 自动创建目录

# 读取当前目录下的所有txt文件
txt_files = Path('.').glob('*.txt')
for txt_file in txt_files:
    with open(txt_file, 'r') as f:
        print(f"处理文件: {txt_file.name}")

路径操作对比表:

操作os.pathpathlib
拼接路径os.path.join('a', 'b')Path('a') / 'b'
获取文件名os.path.basename(path)path.name
获取扩展名os.path.splitext(path)[1]path.suffix
判断是否存在os.path.exists(path)path.exists()
创建目录os.makedirs(path)path.mkdir()

5. 文件读写的瑞士军刀:json、csv、pickle

读取JSON文件:

# ❌ 手动解析,容易出错
import json
with open('data.json', 'r') as f:
    content = f.read()
    data = json.loads(content)  # 两步操作,何必呢?

# ✅ 一行搞定
import json
with open('data.json', 'r') as f:
    data = json.load(f)  # 直接从文件读取并解析

写入JSON文件:

data = {'name': '张三', 'age': 25}

# ✅ 美化输出,人类可读
with open('person.json', 'w', encoding='utf-8') as f:
    json.dump(data, f, ensure_ascii=False, indent=2)

处理CSV文件:

# ❌ 手动处理分隔符,容易出错
with open('data.csv', 'r') as f:
    for line in f:
        fields = line.strip().split(',')
        # 如果字段里包含逗号就炸了...

# ✅ 专业工具,自动处理转义
import csv
with open('data.csv', 'r', encoding='utf-8') as f:
    reader = csv.DictReader(f)  # 自动变成字典
    for row in reader:
        print(row['name'], row['age'])

对象序列化(pickle):

import pickle

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

# 保存对象
person = Person('张三', 25)
with open('person.pkl', 'wb') as f:  # 注意:二进制模式
    pickle.dump(person, f)

# 读取对象
with open('person.pkl', 'rb') as f:  # 注意:二进制模式
    loaded_person = pickle.load(f)
    print(loaded_person.name, loaded_person.age)

实战案例:日志分析工具

学了这么多,来个实战练练手:

from pathlib import Path
import json
from datetime import datetime

def analyze_logs(log_dir='logs'):
    """分析日志文件,统计错误类型"""
    log_path = Path(log_dir)
    error_stats = {}

    # 遍历所有日志文件
    for log_file in log_path.glob('*.log'):
        print(f"分析文件: {log_file.name}")

        with open(log_file, 'r', encoding='utf-8') as f:
            for line_num, line in enumerate(f, 1):
                if 'ERROR' in line:
                    # 提取错误类型(简单示例)
                    error_type = line.split('ERROR')[1].strip()[:50]
                    error_stats[error_type] = error_stats.get(error_type, 0) + 1

    # 保存分析结果
    report = {
        'analysis_time': datetime.now().isoformat(),
        'total_errors': sum(error_stats.values()),
        'error_types': error_stats
    }

    with open('error_report.json', 'w', encoding='utf-8') as f:
        json.dump(report, f, ensure_ascii=False, indent=2)

    print(f"分析完成!发现 {report['total_errors']} 个错误")
    return report

# 运行分析
if __name__ == '__main__':
    analyze_logs()

总结

记住这几个要点,你的Python文件读写技能就能超越80%的程序员:

  1. 永远用with语句 - 自动管理资源,避免忘记关闭文件
  2. 明确指定编码 - 用utf-8,避免中文乱码
  3. 大文件逐行读取 - 节省内存,提高性能
  4. 用pathlib处理路径 - 跨平台兼容,代码更优雅
  5. 善用专业模块 - json、csv、pickle让数据处理更简单

文件读写看似简单,但细节决定成败。掌握了这些技巧,你的代码会更稳定、更高效、更优雅。

下次写文件操作时,别再硬写了,用这些骚操作,让你的同事都投来崇拜的目光!


你在项目中遇到过哪些文件读写的坑?评论区分享一下,让大家都避避坑!