Python文件读写方法

Python文件读写是编程中非常基础且重要的技能,无论是处理数据、保存程序状态还是读取配置信息,都离不开文件操作。本教程将全面介绍Python中文件读写的方法,涵盖基本操作、高级技巧、常见问题及解决方案,帮助您掌握这一核心技能。

1. 文件基础概念

在Python中,文件被视为一个连续的字节序列,每个文件都有一个文件名和路径。文件操作主要涉及三个基本步骤:打开文件、读写文件和关闭文件。Python使用内置的open()函数来处理文件,该函数返回一个文件对象,通过该对象可以对文件进行读写操作。

文件路径分为绝对路径和相对路径。绝对路径是从根目录开始的完整路径,如C:\Users\username\file.txt;相对路径是相对于当前工作目录的路径,如data/file.txt。在Windows系统中,路径分隔符使用反斜杠\,但在Python字符串中反斜杠是转义字符,因此通常使用双反斜杠\\或原始字符串r'path\to\file'。跨平台更推荐使用正斜杠/,因为Python会自动处理路径分隔符。

文件打开模式决定了文件如何被访问:

'r':只读模式(默认)

'w':写入模式(会覆盖已有文件)

'a':追加模式(在文件末尾添加内容)

'x':独占创建模式(文件必须不存在)

'b':二进制模式

't':文本模式(默认)

'+':读写模式

这些模式可以组合使用,如'rb'表示二进制读取模式,'w+'表示读写模式(会覆盖文件)。

2. 打开和关闭文件

打开文件使用open()函数,基本语法为:

file_object = open(file_path, mode='r', encoding=None)

参数说明:

file_path:文件路径(字符串)

mode:打开模式(字符串)

encoding:文件编码(如'utf-8'),文本模式必需

关闭文件使用文件对象的close()方法:

file_object.close()

示例代码:

# 打开文件
file = open('example.txt', 'r', encoding='utf-8')

# 在这里进行文件操作...

# 关闭文件
file.close()

重要说明:必须确保文件被正确关闭,否则可能导致资源泄露或数据损坏。更安全的方法是使用with语句(上下文管理器),它会在代码块结束时自动关闭文件,即使在操作过程中发生异常。

with open('example.txt', 'r', encoding='utf-8') as file:
    # 文件操作
    content = file.read()
    print(content)
# 文件已自动关闭

3. 读取文本文件

3.1. 读取整个文件

使用read()方法读取整个文件内容为一个字符串:

with open('example.txt', 'r', encoding='utf-8') as file:
    content = file.read()
    print(content)

注意事项:对于大文件,一次性读取全部内容可能会消耗大量内存,此时应考虑逐行读取或分块读取。

3.2. 逐行读取

使用readline()方法读取单行内容:

with open('example.txt', 'r', encoding='utf-8') as file:
    line = file.readline()
    while line:
        print(line.strip())  # 去除行尾换行符
        line = file.readline()

或者使用readlines()方法读取所有行到一个列表:

with open('example.txt', 'r', encoding='utf-8') as file:
    lines = file.readlines()
    for line in lines:
        print(line.strip())

更Pythonic的方式:直接迭代文件对象,逐行读取,内存效率高:

with open('example.txt', 'r', encoding='utf-8') as file:
    for line in file:
        print(line.strip())

3.3. 按固定大小读取

使用read(size)方法按指定大小读取(单位为字节):

with open('example.txt', 'r', encoding='utf-8') as file:
    chunk_size = 100  # 每次读取100个字符
    while True:
        chunk = file.read(chunk_size)
        if not chunk:  # 到达文件末尾
            break
        print(chunk, end='')

4. 写入文本文件

4.1. 写入字符串

使用write()方法写入字符串,返回写入的字符数:

with open('output.txt', 'w', encoding='utf-8') as file:
    file.write('Hello, World!\n')
    file.write('This is a test file.\n')

注意事项:write()方法不会自动添加换行符,需要手动添加\n

4.2. 写入多行

使用writelines()方法写入字符串列表,但不会自动添加换行符:

lines = ['First line\n', 'Second line\n', 'Third line\n']
with open('output.txt', 'w', encoding='utf-8') as file:
    file.writelines(lines)

4.3. 追加内容

使用追加模式'a'在文件末尾添加内容:

with open('output.txt', 'a', encoding='utf-8') as file:
    file.write('This line will be appended.\n')

5. 二进制文件操作

对于非文本文件(如图片、音频、视频),需要使用二进制模式(添加'b'):

# 读取二进制文件
with open('image.jpg', 'rb') as file:
    binary_data = file.read()
    print(len(binary_data), 'bytes read')

# 写入二进制文件
with open('copy.jpg', 'wb') as file:
    file.write(binary_data)

二进制模式下不能使用encoding参数,因为数据是原始字节流。

6. 文件指针操作

文件指针表示当前读写位置,Python提供两个方法控制指针位置:

tell():返回当前指针位置(从文件开头算起的字节数)

seek(offset, whence):移动指针位置

offset:偏移量(字节数)

whence:参考位置(0:文件开头,1:当前位置,2:文件末尾)

示例代码:

with open('example.txt', 'r+b') as file:  # 读写二进制模式
    file.write(b'0123456789')  # 写入10个字节
    print(file.tell())  # 输出当前指针位置:10

    file.seek(0)  # 移动到文件开头
    data = file.read(3)  # 读取3个字节:b'012'
    print(data)

    file.seek(2, 1)  # 从当前位置移动2个字节(位置从3到5)
    print(file.read(3))  # 读取位置5-7:b'567'

    file.seek(-5, 2)  # 从文件末尾移动5个字节(位置5)
    print(file.read())  # 读取位置5到末尾:b'56789'

注意事项:

文本模式下,seek()只能相对于文件开头移动(whence只能是0)

非ASCII字符在文本模式下可能占用多个字节,指针位置可能不准确

7. 文件与目录操作

Python的os模块提供了丰富的文件和目录操作功能:

7.1. 基本路径操作

import os

# 获取当前工作目录
current_dir = os.getcwd()
print('Current directory:', current_dir)

# 改变工作目录
os.chdir('/path/to/directory')

# 创建目录
os.mkdir('new_folder')  # 创建单层目录
os.makedirs('parent/child', exist_ok=True)  # 创建多层目录

# 列出目录内容
entries = os.listdir('.')
print('Entries:', entries)

# 检查路径是否存在
print('File exists:', os.path.exists('example.txt'))

# 检查是否是文件或目录
print('Is file:', os.path.isfile('example.txt'))
print('Is directory:', os.path.isdir('example.txt'))

7.2. 路径拼接与分割

# 拼接路径(跨平台)
file_path = os.path.join('data', 'files', 'example.txt')
print('Joined path:', file_path)

# 分割路径
dirname, filename = os.path.split(file_path)
print('Directory:', dirname)
print('Filename:', filename)

# 获取绝对路径
abs_path = os.path.abspath(file_path)
print('Absolute path:', abs_path)

# 获取文件名和扩展名
filename, ext = os.path.splitext(file_path)
print('Filename without extension:', filename)
print('Extension:', ext)

7.3. 文件管理操作

# 重命名文件或目录
os.rename('old_name.txt', 'new_name.txt')

# 删除文件
os.remove('unwanted_file.txt')

# 删除空目录
os.rmdir('empty_folder')

# 删除目录及其内容(谨慎使用)
import shutil
shutil.rmtree('non_empty_folder')

# 复制文件
shutil.copy('source.txt', 'destination.txt')

# 移动文件(相当于重命名)
shutil.move('source.txt', 'destination.txt')

8. 常见格式文件处理

8.1. CSV文件处理

使用内置的csv模块处理CSV文件:

import csv

# 写入CSV文件
with open('data.csv', 'w', newline='', encoding='utf-8') as file:
    writer = csv.writer(file)
    writer.writerow(['Name', 'Age', 'City'])
    writer.writerow(['Alice', 25, 'New York'])
    writer.writerow(['Bob', 30, 'Los Angeles'])

# 读取CSV文件
with open('data.csv', 'r', encoding='utf-8') as file:
    reader = csv.reader(file)
    for row in reader:
        print(', '.join(row))

使用DictReaderDictWriter处理带表头的CSV:

# 写入带表头的CSV
with open('data.csv', 'w', newline='', encoding='utf-8') as file:
    fieldnames = ['Name', 'Age', 'City']
    writer = csv.DictWriter(file, fieldnames=fieldnames)
    writer.writeheader()
    writer.writerow({'Name': 'Alice', 'Age': 25, 'City': 'New York'})
    writer.writerow({'Name': 'Bob', 'Age': 30, 'City': 'Los Angeles'})

# 读取带表头的CSV
with open('data.csv', 'r', encoding='utf-8') as file:
    reader = csv.DictReader(file)
    for row in reader:
        print(row['Name'], row['Age'], row['City'])

8.2. JSON文件处理

使用内置的json模块处理JSON文件:

import json

# 写入JSON文件
data = {
    'name': 'John Doe',
    'age': 35,
    'is_student': False,
    'courses': ['Math', 'Physics', 'Chemistry']
}

with open('data.json', 'w', encoding='utf-8') as file:
    json.dump(data, file, indent=4)  # indent=4美化输出

# 读取JSON文件
with open('data.json', 'r', encoding='utf-8') as file:
    loaded_data = json.load(file)
    print(loaded_data)
    print('Name:', loaded_data['name'])
    print('First course:', loaded_data['courses'][0])

处理JSON字符串:

# 将Python对象转换为JSON字符串
json_str = json.dumps(data, indent=4)
print(json_str)

# 将JSON字符串解析为Python对象
parsed_data = json.loads(json_str)
print(parsed_data)

9. 错误处理与异常捕获

文件操作中常见的异常包括:

FileNotFoundError:文件或目录不存在

PermissionError:权限不足

IsADirectoryError:对目录进行了文件操作

NotADirectoryError:对文件进行了目录操作

FileExistsError:文件已存在(在独占创建模式下)

OSError:操作系统相关错误

使用try...except捕获异常:

try:
    with open('nonexistent_file.txt', 'r', encoding='utf-8') as file:
        content = file.read()
except FileNotFoundError:
    print('Error: File not found!')
except PermissionError:
    print('Error: Permission denied!')
except OSError as e:
    print(f'Error: {e}')
else:
    print('File read successfully')
    print(content)

更健壮的文件操作函数:

def read_file_safely(file_path):
    try:
        with open(file_path, 'r', encoding='utf-8') as file:
            return file.read()
    except FileNotFoundError:
        print(f"Error: File '{file_path}' not found!")
    except PermissionError:
        print(f"Error: No permission to read '{file_path}'!")
    except OSError as e:
        print(f"Error reading file '{file_path}': {e}")
    return None

content = read_file_safely('example.txt')
if content is not None:
    print(content)

10. 高级文件操作

10.1. 内存映射文件

对于大文件,可以使用mmap模块创建内存映射文件,实现高效访问:

import mmap

with open('large_file.bin', 'r+b') as file:
    # 创建内存映射
    with mmap.mmap(file.fileno(), 0, access=mmap.ACCESS_READ) as mm:
        # 读取前100个字节
        data = mm.read(100)
        print(data)

        # 查找字节序列
        pos = mm.find(b'pattern')
        if pos != -1:
            print(f"Pattern found at position {pos}")

10.2. 临时文件处理

使用tempfile模块创建临时文件:

import tempfile

# 创建临时文件
with tempfile.NamedTemporaryFile(mode='w+', delete=False) as temp_file:
    temp_file.write('Temporary data\n')
    temp_file.write('Will be deleted after context\n')
    temp_path = temp_file.name  # 获取临时文件路径

# 临时文件仍然存在(因为delete=False)
print(f"Temporary file created at: {temp_path}")

# 再次读取临时文件
with open(temp_path, 'r') as file:
    print(file.read())

# 手动删除临时文件
import os
os.unlink(temp_path)

10.3. 文件压缩

使用gzip模块处理压缩文件:

import gzip

# 写入压缩文件
with gzip.open('compressed.gz', 'wt', encoding='utf-8') as file:
    file.write('This text will be compressed\n')
    file.write('Compressed with gzip\n')

# 读取压缩文件
with gzip.open('compressed.gz', 'rt', encoding='utf-8') as file:
    print(file.read())

10.4. 文件遍历与处理

使用os.walk()递归遍历目录:

import os

def process_files(root_dir):
    for dirpath, dirnames, filenames in os.walk(root_dir):
        print(f"Directory: {dirpath}")
        for filename in filenames:
            file_path = os.path.join(dirpath, filename)
            print(f"  File: {file_path}")
            # 这里可以添加文件处理逻辑
            if filename.endswith('.txt'):
                process_text_file(file_path)

def process_text_file(file_path):
    with open(file_path, 'r', encoding='utf-8') as file:
        print(f"    Processing {file_path}...")
        # 处理文本文件内容
        # ...

# 使用示例
process_files('data')

11. 实例综合应用

11.1. 文件批量重命名

下面是一个实用的脚本,用于批量重命名目录中的文件:

import os

def batch_rename(directory, prefix, start_num=1, extension=None):
    """批量重命名目录中的文件

    Args:
        directory: 目标目录
        prefix: 新文件名前缀
        start_num: 起始编号
        extension: 只重命名指定扩展名的文件(如'.txt')
    """
    if not os.path.isdir(directory):
        print(f"Error: '{directory}' is not a valid directory!")
        return

    num = start_num
    for filename in os.listdir(directory):
        file_path = os.path.join(directory, filename)

        # 跳过子目录
        if os.path.isdir(file_path):
            continue

        # 检查文件扩展名
        if extension is not None and not filename.lower().endswith(extension.lower()):
            continue

        # 获取文件扩展名
        _, ext = os.path.splitext(filename)

        # 构建新文件名
        new_filename = f"{prefix}_{num:03d}{ext}"
        new_path = os.path.join(directory, new_filename)

        # 重命名文件
        os.rename(file_path, new_path)
        print(f"Renamed: {filename} -> {new_filename}")

        num += 1

# 使用示例:重命名当前目录下所有txt文件
batch_rename('.', 'document', extension='.txt')

11.2. 文件内容搜索工具

这个工具可以在目录中搜索包含特定文本的文件:

import os

def search_files(directory, search_text, extension='.txt'):
    """在目录中搜索包含特定文本的文件

    Args:
        directory: 要搜索的目录
        search_text: 要搜索的文本
        extension: 要搜索的文件扩展名
    """
    results = []
    for root, _, files in os.walk(directory):
        for filename in files:
            if not filename.lower().endswith(extension.lower()):
                continue

            file_path = os.path.join(root, filename)
            try:
                with open(file_path, 'r', encoding='utf-8') as file:
                    for line_num, line in enumerate(file, 1):
                        if search_text in line:
                            result = {
                                'file': file_path,
                                'line_number': line_num,
                                'line': line.strip()
                            }
                            results.append(result)
            except (UnicodeDecodeError, PermissionError):
                # 跳过无法读取的文件
                continue

    return results

# 使用示例:在当前目录下搜索包含"Python"的txt文件
results = search_files('.', 'Python', '.txt')
for result in results:
    print(f"{result['file']}:{result['line_number']} - {result['line']}")

11.3. 配置文件读写

下面是一个简单的配置文件处理类,支持读写INI风格配置:

import configparser

class ConfigManager:
    def __init__(self, config_file):
        self.config_file = config_file
        self.config = configparser.ConfigParser()
        self.load_config()

    def load_config(self):
        """加载配置文件"""
        if os.path.exists(self.config_file):
            self.config.read(self.config_file, encoding='utf-8')

    def save_config(self):
        """保存配置到文件"""
        with open(self.config_file, 'w', encoding='utf-8') as file:
            self.config.write(file)

    def get(self, section, option, fallback=None):
        """获取配置项"""
        return self.config.get(section, option, fallback=fallback)

    def set(self, section, option, value):
        """设置配置项"""
        if not self.config.has_section(section):
            self.config.add_section(section)
        self.config.set(section, option, str(value))

    def get_section(self, section):
        """获取整个配置段"""
        if self.config.has_section(section):
            return dict(self.config.items(section))
        return {}

    def update_section(self, section, data):
        """更新配置段"""
        if not self.config.has_section(section):
            self.config.add_section(section)
        for key, value in data.items():
            self.config.set(section, key, str(value))

# 使用示例
config = ConfigManager('settings.ini')

# 设置配置
config.set('Database', 'host', 'localhost')
config.set('Database', 'port', '5432')
config.set('Database', 'username', 'admin')

config.set('App', 'debug', 'True')
config.set('App', 'log_level', 'info')

# 保存配置
config.save_config()

# 读取配置
host = config.get('Database', 'host', '127.0.0.1')
port = config.get('Database', 'port')
debug = config.get('App', 'debug', 'False')

print(f"Database connection: {host}:{port}")
print(f"Debug mode: {debug}")

# 获取整个配置段
db_config = config.get_section('Database')
print("Database config:", db_config)

12. 总结

本教程全面介绍了Python文件读写的方法,从基本操作到高级技巧,涵盖了文本文件、二进制文件、常见格式文件(CSV、JSON)的处理方式,以及文件和目录管理、错误处理、内存映射、临时文件、文件压缩等高级主题。通过丰富的代码示例和详细解释,您应该能够掌握:

使用open()函数和with语句安全地打开和关闭文件

多种读取文件的方法(整个文件、逐行、分块)

写入文件的基本技巧(覆盖写入、追加内容)

二进制文件的处理方法

文件指针的操作(tell()seek()

使用osshutil模块进行文件和目录管理

处理CSV和JSON格式文件的技巧

健壮的文件操作(异常捕获和错误处理)

高级文件操作(内存映射、临时文件、文件压缩)

实用工具开发(批量重命名、文件搜索、配置文件处理)

文件操作是Python编程中不可或缺的一部分,掌握这些技能将为您处理各种数据任务提供强大的支持。通过实践这些示例,并根据自己的需求进行扩展,您将能够高效地处理各种文件操作场景。记住,在处理文件时要特别注意资源管理和错误处理,确保程序的健壮性和可靠性。

发表回复

后才能评论