首页 > 解决方案 > 在 Python 中擦除文本文件的一部分

问题描述

我的硬盘中有一个非常大的文本文件。它有大约 800 万个用逗号分隔的 json 文件,我想删除最后一个 json ;但是,因为它真的很大,我无法通过常规编辑器(Notepad++、Sublime、Visual Studio Code……)来完成。所以,我决定使用 Python,但我不知道如何使用 python 擦除现有文件的一部分。任何形式的帮助将不胜感激。

PS:我的文件有这样的结构:

json1, json2, json3, ...
when each json looks like {"a":"something", "b":"something", "c":"something"}

标签: python-3.xtexttext-mining

解决方案


由于您只希望从文件中删除最后一个 JSON 对象,因此更有效的方法是识别文件末尾的第一个有效 JSON 对象,并从该 JSON 对象前面逗号所在的位置截断文件。

这可以通过从文件末尾向后查找和读取来完成,一次一个相对较小的块,将缓冲区拆分为{(因为它标志着 JSON 对象的开始),然后一次一个地添加片段到一个缓冲区,直到缓冲区可解析为 JSON 对象(这使得代码能够处理嵌套的 dict 结构),此时您应该从前面的片段中找到前面的逗号并将逗号添加到缓冲区中,这样最后,您可以将文件查找到缓冲区开始的位置并截断文件:

import json
chunk_size = 1024
with open('file.txt', 'rb+') as f:
    f.seek(-chunk_size, 2)
    buffer = ''
    while True:
        fragments = f.read(chunk_size).decode().split('{')
        f.seek(-chunk_size * 2, 1)
        i = len(fragments)
        for fragment in fragments[:0:-1]:
            i -= 1
            buffer = '{%s%s' % (fragment, buffer)
            try:
                json.loads(buffer)
                break
            except ValueError:
                pass
        else:
            buffer = fragments[0] + buffer
            continue
        break
    next_fragment = fragments[i - 1]
    # if we don't have a comma in the preceding fragment and it is already the first
    # fragment, we need to read backwards a little more
    if i == 1 and ',' not in fragments[0]:
        f.seek(-2, 1)
        next_fragment = f.read(2).decode() + next_fragment
    buffer = next_fragment[next_fragment.rindex(','):] + buffer
    f.seek(-len(buffer.encode()), 2)
    f.truncate()

推荐阅读