【问题标题】:Replace comma with pipe delimiter within the same file using python使用python在同一文件中用管道分隔符替换逗号
【发布时间】:2025-12-03 05:25:01
【问题描述】:

以下是代码,该代码工作正常,我得到一个以管道作为分隔符的输出文件。但是,我不希望生成新文件,而是希望将现有文件替换为管道分隔符而不是逗号。感谢您的投入。我是 python 新手,在旅途中学习它。

with open(dst1,encoding='utf-8',errors='ignore') as input_file:
    with open(dst2, 'w',encoding='utf-8',errors='ignore', newline='') as output_file:
        reader = csv.DictReader(input_file, delimiter=',')
        writer = csv.DictWriter(output_file, reader.fieldnames,'uft-8', delimiter='|')
        writer.writeheader()
        writer.writerows(reader)

【问题讨论】:

  • 好吧,如果一切都适合内存,只需保留数据并在之后重写它们。如果没有,就做一个 temp_file
  • 一个更谨慎的策略可能是重命名旧文件,然后用旧文件的名称写入新文件。然后您可以在发生错误时恢复。
  • @snakecharmerb:通常你会反其道而行之;写入一个新文件,然后仅当新文件已完全写入时,才用新文件原子地替换原始文件。
  • @ShadowRanger 当然 - 我只是建议谨慎,因为 OP 正在学习,但工业强度的鲁棒性很好。

标签: python python-3.x file csv


【解决方案1】:

唯一真正安全的方法是写入一个新文件,然后用新文件自动替换旧文件。任何其他解决方案都存在断电时数据丢失/损坏的风险。简单的方法是使用the tempfile module 在同一目录下创建一个临时文件(这样atomic replace 就可以了):

import os.path
import tempfile

with open(dst1, encoding='utf-8', errors='ignore', newline='') as input_file, \
     tempfile.NamedTemporaryFile(mode='w', encoding='utf-8', newline='',
                                 dir=os.path.dirname(dst1), delete=False) as tf:
    try:
        reader = csv.DictReader(input_file)
        writer = csv.DictWriter(tf, reader.fieldnames, delimiter='|')
        writer.writeheader()
        writer.writerows(reader)
    except:
        # On error, remove temporary before reraising exception
        os.remove(tf.name)
        raise
    else:
        # else is optional, if you want to be extra careful that all
        # data is synced to disk to reduce risk that metadata updates
        # before data synced to disk:
        tf.flush()
        os.fsync(tf.fileno())

# Atomically replace original file with temporary now that with block exited and
# data fully written
try:
    os.replace(tf.name, dst1)
except:
    # On error, remove temporary before reraising exception
    os.remove(tf.name)
    raise

【讨论】:

  • 谢谢影子游侠!!
【解决方案2】:

由于您只是将单个字符分隔符从一个替换为另一个,因此文件大小或任何未被替换的字符的位置都不会发生变化。因此,这是在r+ 模式下打开文件以允许将处理后的内容写回同时读取的同一个文件的完美场景,因此不需要临时文件:

with open(dst, encoding='utf-8', errors='ignore') as input_file, open(dst, 'r+', encoding='utf-8', errors='ignore', newline='') as output_file:
    reader = csv.DictReader(input_file, delimiter=',')
    writer = csv.DictWriter(output_file, reader.fieldnames, 'uft-8', delimiter='|')
    writer.writeheader()
    writer.writerows(reader)

编辑:请阅读@ShadowRanger 的评论,了解这种方法的局限性。

【讨论】:

  • 不能保证文件大小实际上不会改变。 csv 模块的默认引用规则是csv.QUOTE_MINIMAL,它只引用包含分隔符、引号字符或行终止符的字段;如果将分隔符从, 更改为|,则以前由于嵌入逗号而需要引用的字段如果不包含|,则不会被引用。如果脚本在中途被终止(无论出于何种原因;断电、程序崩溃、用户按 Ctrl-C),您最终会得到新旧数据的混合。
  • 好点。我会在这里留下我的答案,以防 OP 的实际 CSV 文件不涉及任何引用的字段并且只想要一些最小的东西。但我同意这通常不是一个可靠的解决方案。
  • 注意:您可以通过在writerows 调用之后添加output_file.truncate() 来解决文件大小问题(尽管不是断电/崩溃/Ctrl-C 的问题)。保留(相对不太可能)新文件数据大得多以至于在您开始缓冲文件中的数据之前覆盖文件的一部分的可能性,但至少它不会冒尾随垃圾的风险。
  • 两种解决方案都有效。但是,我坚信使用 ShadowRanger 的解决方案感谢您的帮助,感谢您的宝贵时间。
  • 您好,在同一张纸条上,我的 csv 文件中的一列包含 |在数据之间。我该如何删除它。谢谢!
【解决方案3】:

我不完全确定,但如果文件不是太大,您可以使用 read_csv 将文件加载到 pandas 中,然后使用所需的分隔符使用您喜欢的分隔符使用 to_csv 函数将其保存。比如——

import pandas as pd
data = pd.read_csv(input_file, encoding='utf-8')
data.to_csv(input_file, sep='|', encoding='utf-8')

希望这会有所帮助!

【讨论】:

  • 这不会替换原始文件...即使您通过将input_file 也传递给to_csv 来更改它,它也存在数据损坏的风险(因为它会通过截断文件来重写文件,然后写出新数据,中途崩溃将丢失数据)。除此之外,如果 OP 尚未使用 pandas,则将其添加为依赖项是一个非常重量级的解决方案。
  • 是的,我同意你的看法。但我认为这是一个巧妙的解决方案。感谢您提醒我