MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Python文件写入多行数据的方法

2022-03-266.6k 阅读

一、使用 write() 方法写入多行数据

1.1 手动拼接换行符

在Python中,文件对象的 write() 方法用于向文件中写入字符串。要写入多行数据,我们可以手动在每个字符串后添加换行符 \n。下面是一个简单的示例:

try:
    with open('example.txt', 'w') as file:
        lines = ["第一行内容\n", "第二行内容\n", "第三行内容\n"]
        for line in lines:
            file.write(line)
except IOError as e:
    print(f"写入文件时发生错误: {e}")

在上述代码中,我们首先使用 with open('example.txt', 'w') 以写入模式打开一个名为 example.txt 的文件。with 语句会在代码块结束时自动关闭文件,确保资源的正确管理。

然后,我们定义了一个包含多行内容的列表 lines,每个元素后面都手动添加了换行符 \n。通过循环遍历这个列表,并使用 file.write(line) 将每一行写入文件。

如果在写入过程中发生 IOError 异常,我们会捕获并打印错误信息。

1.2 动态生成内容并写入

实际应用中,数据可能是动态生成的,而不是预先定义好的列表。例如,我们可能需要写入一系列数字对应的平方值:

try:
    with open('squares.txt', 'w') as file:
        for i in range(1, 11):
            square = i * i
            line = f"数字 {i} 的平方是 {square}\n"
            file.write(line)
except IOError as e:
    print(f"写入文件时发生错误: {e}")

这段代码会打开 squares.txt 文件,然后通过 for 循环计算从1到10的数字的平方,并将每一个结果以格式化字符串的形式写入文件,每个字符串后添加换行符。

二、使用 writelines() 方法

2.1 基本使用

writelines() 方法也是文件对象的一个方法,它接受一个字符串序列(如列表、元组等)作为参数,并将这些字符串依次写入文件。与 write() 方法不同的是,writelines() 不会自动在每个字符串后添加换行符,因此我们需要在字符串序列的每个元素中自行包含换行符。

try:
    lines = ["第一行内容\n", "第二行内容\n", "第三行内容\n"]
    with open('example_writelines.txt', 'w') as file:
        file.writelines(lines)
except IOError as e:
    print(f"写入文件时发生错误: {e}")

在这个示例中,我们创建了一个包含多行内容且每行都有换行符的列表 lines。然后通过 file.writelines(lines) 将列表中的所有内容写入 example_writelines.txt 文件。

2.2 生成器与 writelines() 结合

我们可以利用生成器来动态生成要写入文件的内容,然后与 writelines() 方法结合使用。例如,生成一系列斐波那契数列并写入文件:

def fibonacci_generator(n):
    a, b = 0, 1
    for _ in range(n):
        yield a
        a, b = b, a + b


try:
    with open('fibonacci.txt', 'w') as file:
        fib_numbers = [f"{num}\n" for num in fibonacci_generator(10)]
        file.writelines(fib_numbers)
except IOError as e:
    print(f"写入文件时发生错误: {e}")

在上述代码中,我们定义了一个 fibonacci_generator 生成器函数,它生成指定数量的斐波那契数列。然后,我们使用列表推导式将生成器生成的每个斐波那契数转换为包含换行符的字符串,并存储在 fib_numbers 列表中。最后,通过 file.writelines(fib_numbers) 将这些字符串写入 fibonacci.txt 文件。

三、格式化写入多行数据

3.1 使用 format() 方法

format() 方法是Python字符串的一个格式化方法,我们可以利用它来格式化要写入文件的多行数据。

try:
    data = [
        {'name': 'Alice', 'age': 25},
        {'name': 'Bob', 'age': 30},
        {'name': 'Charlie', 'age': 35}
    ]
    with open('formatted.txt', 'w') as file:
        for item in data:
            line = "姓名:{name},年龄:{age}\n".format(name=item['name'], age=item['age'])
            file.write(line)
except IOError as e:
    print(f"写入文件时发生错误: {e}")

在这个例子中,我们有一个包含字典的列表 data,每个字典表示一个人的信息。通过循环遍历这个列表,使用 format() 方法将字典中的数据格式化到字符串中,并添加换行符,最后通过 file.write(line) 写入文件。

3.2 f - 字符串格式化

从Python 3.6开始,引入了f - 字符串(格式化字符串字面值),它提供了一种更简洁直观的格式化字符串的方式。

try:
    data = [
        {'name': 'Alice', 'age': 25},
        {'name': 'Bob', 'age': 30},
        {'name': 'Charlie', 'age': 35}
    ]
    with open('f_string_formatted.txt', 'w') as file:
        for item in data:
            line = f"姓名:{item['name']},年龄:{item['age']}\n"
            file.write(line)
except IOError as e:
    print(f"写入文件时发生错误: {e}")

这里,我们通过f - 字符串直接将字典中的值嵌入到字符串中,然后添加换行符并写入文件。与 format() 方法相比,f - 字符串的语法更加简洁明了,在处理多行数据的格式化写入时更加方便。

四、追加模式下写入多行数据

4.1 使用 write() 追加

在追加模式下写入多行数据,我们只需要将文件打开模式从 'w'(写入模式,会覆盖原有内容)改为 'a'(追加模式,会在文件末尾添加内容)。

try:
    with open('append_example.txt', 'a') as file:
        lines = ["追加的第一行内容\n", "追加的第二行内容\n", "追加的第三行内容\n"]
        for line in lines:
            file.write(line)
except IOError as e:
    print(f"写入文件时发生错误: {e}")

在这个示例中,append_example.txt 文件以追加模式打开,然后将 lines 列表中的内容依次追加到文件末尾。每次运行这段代码,都会在文件末尾添加新的内容,而不会覆盖原有内容。

4.2 使用 writelines() 追加

同样,我们也可以在追加模式下使用 writelines() 方法。

try:
    lines = ["追加的第一行内容\n", "追加的第二行内容\n", "追加的第三行内容\n"]
    with open('append_writelines_example.txt', 'a') as file:
        file.writelines(lines)
except IOError as e:
    print(f"写入文件时发生错误: {e}")

这里,append_writelines_example.txt 文件以追加模式打开,通过 file.writelines(lines)lines 列表中的字符串追加到文件末尾。

五、写入多行数据时的编码问题

5.1 默认编码

在Python中,当我们使用 open() 函数打开文件时,如果不指定编码参数,默认编码取决于操作系统。在Windows上,默认编码通常是 cp1252,而在Linux和macOS上,默认编码通常是 utf - 8

例如,以下代码在不同操作系统上可能会因为默认编码不同而产生不同的结果:

try:
    with open('encoding_example.txt', 'w') as file:
        file.write('你好,世界!\n')
except IOError as e:
    print(f"写入文件时发生错误: {e}")

如果在Windows系统上以默认编码 cp1252 写入包含非ASCII字符(如中文)的内容,可能会导致编码错误。

5.2 指定编码

为了确保在不同操作系统上都能正确处理各种字符编码,我们应该在打开文件时显式指定编码。最常用的编码是 utf - 8,它支持几乎所有的字符集。

try:
    with open('utf8_encoding_example.txt', 'w', encoding='utf - 8') as file:
        file.write('你好,世界!\n')
except IOError as e:
    print(f"写入文件时发生错误: {e}")

在这个示例中,我们通过 encoding='utf - 8' 显式指定了文件的编码为 utf - 8,这样无论在何种操作系统上运行,都能正确写入包含中文字符等非ASCII字符的内容。

当我们使用 writelines() 方法写入多行数据时,同样需要注意编码问题。例如:

try:
    lines = ["你好,世界1!\n", "你好,世界2!\n", "你好,世界3!\n"]
    with open('utf8_writelines_example.txt', 'w', encoding='utf - 8') as file:
        file.writelines(lines)
except IOError as e:
    print(f"写入文件时发生错误: {e}")

这里同样指定了 utf - 8 编码,以确保多行内容能正确写入文件。

六、处理二进制文件的多行写入

6.1 基本概念

在处理文本文件时,我们可以直接写入字符串并通过换行符来实现多行写入。但对于二进制文件(如图片、音频、视频等),情况有所不同。二进制文件没有字符编码和换行符的概念,数据是以字节序列的形式存储的。

如果我们要在二进制文件中模拟“多行”写入,通常是根据文件格式的特定规则来进行数据的分段写入。

6.2 示例:写入二进制图像文件(简单示意)

假设我们有一个简单的图像数据表示,每行像素数据是一个字节数组,我们可以将这些字节数组依次写入二进制文件来模拟多行写入。

import struct


try:
    # 模拟图像数据,每行10个像素,每个像素用1个字节表示
    image_data = [
        bytearray([10, 20, 30, 40, 50, 60, 70, 80, 90, 100]),
        bytearray([110, 120, 130, 140, 150, 160, 170, 180, 190, 200]),
        bytearray([210, 220, 230, 240, 250, 255, 254, 253, 252, 251])
    ]
    with open('image.bin', 'wb') as file:
        for row in image_data:
            file.write(struct.pack(f"{len(row)}B", *row))
except IOError as e:
    print(f"写入文件时发生错误: {e}")

在这个示例中,我们使用 struct.pack() 函数将字节数组按照指定格式(这里是每个字节用 B 表示)打包成二进制数据,然后通过 file.write() 依次写入 image.bin 文件。虽然这里不是真正意义上的文本文件的多行写入,但通过这种方式,我们可以在二进制文件中按照特定规则分段写入数据,类似多行的概念。

七、异常处理与错误恢复

7.1 常见异常类型

在进行文件写入操作时,可能会遇到各种异常。常见的异常类型包括:

  • IOError:这是一个通用的I/O异常,当文件操作(如打开、写入、读取等)发生错误时会引发。在Python 3中,IOError 被合并到 OSError 中,因此捕获 OSError 可以处理大多数I/O相关的错误。
  • FileNotFoundError:当尝试打开一个不存在的文件进行写入(如果模式要求文件必须存在)时会引发此异常。例如,在以 'r +' 模式打开文件,但文件不存在时就会触发。
  • PermissionError:当没有足够的权限来执行文件操作时会引发此异常。比如,尝试在一个没有写入权限的目录中创建文件。

7.2 异常处理策略

为了确保程序的健壮性,我们需要合理地处理这些异常。以下是一些常见的异常处理策略:

  • 捕获并记录错误:在捕获到异常时,我们可以记录错误信息,以便后续排查问题。例如,使用Python的 logging 模块:
import logging


try:
    with open('error_example.txt', 'w') as file:
        file.write('测试内容')
except OSError as e:
    logging.error(f"写入文件时发生错误: {e}")
  • 提供友好的用户提示:如果程序是面向用户的,捕获异常后可以向用户提供友好的错误提示,而不是让用户看到原始的异常堆栈信息。
try:
    with open('user_friendly.txt', 'w') as file:
        file.write('测试内容')
except OSError as e:
    print("很抱歉,写入文件时出现问题。请检查文件路径和权限。")
  • 尝试恢复操作:在某些情况下,我们可以尝试在捕获异常后进行一些恢复操作。例如,如果是因为文件被占用导致写入失败,可以尝试等待一段时间后再次尝试。
import time


retry_count = 0
while retry_count < 3:
    try:
        with open('retry_example.txt', 'w') as file:
            file.write('测试内容')
        break
    except OSError as e:
        print(f"写入文件失败,尝试重试(第 {retry_count + 1} 次)...")
        time.sleep(1)
        retry_count += 1
if retry_count == 3:
    print("多次重试后仍失败,请检查问题。")

在这个示例中,我们尝试最多3次写入文件,如果失败则等待1秒后再次尝试。如果3次都失败,则提示用户检查问题。

通过合理的异常处理,我们可以使程序在面对文件写入错误时更加稳定和健壮,提高用户体验。

八、性能优化

8.1 批量写入

在写入大量数据时,频繁调用 write()writelines() 方法可能会导致性能问题,因为每次调用都涉及系统I/O操作。一种优化方法是批量收集数据,然后一次性写入。

例如,我们要写入10000行数据:

try:
    buffer_size = 1000
    lines = []
    with open('batch_write_example.txt', 'w') as file:
        for i in range(10000):
            line = f"第 {i + 1} 行内容\n"
            lines.append(line)
            if len(lines) == buffer_size:
                file.writelines(lines)
                lines = []
        if lines:
            file.writelines(lines)
except IOError as e:
    print(f"写入文件时发生错误: {e}")

在这个示例中,我们设置了一个缓冲区大小 buffer_size 为1000。每次生成一行数据后,将其添加到 lines 列表中。当 lines 列表的长度达到 buffer_size 时,一次性通过 file.writelines(lines) 将这些数据写入文件,并清空 lines 列表。最后,如果 lines 列表中还有剩余数据,也将其写入文件。这样可以减少系统I/O操作的次数,提高写入性能。

8.2 使用缓冲区参数

open() 函数有一个 buffering 参数,用于控制文件的缓冲策略。默认情况下,buffering 的值为 - 1,表示使用系统默认的缓冲策略。

我们可以将 buffering 设置为0(无缓冲)、1(行缓冲)或大于1的整数(表示缓冲区大小)来优化性能。

  • 无缓冲(buffering = 0:这种情况下,数据会立即写入文件,不会经过缓冲区。但频繁的直接写入会导致性能下降,因为每次写入都直接与存储设备交互,适用于对数据实时性要求极高且写入数据量极小的场景。
try:
    with open('unbuffered_example.txt', 'w', buffering = 0) as file:
        for i in range(10):
            file.write(f"第 {i + 1} 行内容\n")
except IOError as e:
    print(f"写入文件时发生错误: {e}")
  • 行缓冲(buffering = 1:数据会在遇到换行符时写入文件,适用于需要实时显示输出的场景,如日志文件。
try:
    with open('line_buffered_example.txt', 'w', buffering = 1) as file:
        for i in range(10):
            file.write(f"第 {i + 1} 行内容\n")
except IOError as e:
    print(f"写入文件时发生错误: {e}")
  • 自定义缓冲区大小(buffering > 1:我们可以指定缓冲区的大小,当缓冲区满时,数据会被写入文件。合理设置缓冲区大小可以减少I/O操作次数,提高性能。
try:
    buffer_size = 8192  # 8KB缓冲区
    with open('custom_buffered_example.txt', 'w', buffering = buffer_size) as file:
        for i in range(10000):
            file.write(f"第 {i + 1} 行内容\n")
except IOError as e:
    print(f"写入文件时发生错误: {e}")

在实际应用中,需要根据具体的业务场景和数据量来选择合适的缓冲策略和缓冲区大小,以达到最佳的性能优化效果。

通过上述各种方法的介绍,从基本的写入方法到异常处理、性能优化等方面,我们全面了解了在Python中如何高效、稳定地进行文件的多行数据写入操作。在实际编程中,应根据具体需求选择最合适的方法,并注意编码、异常处理等细节,以确保程序的正确性和健壮性。