我的硬盘中有一个文本文件非常大。它有大约800万个json文件,用逗号分隔,我想删除最后一个json;但是,因为它非常大,我无法通过常规编辑器(Notepad ++,Sublime,Visual Studio Code,...)来实现。所以,我决定使用Python,但我不知道如何使用python擦除现有文件的一部分。任何形式的帮助将不胜感激。
P.S:我的文件有这样的结构:
json1, json2, json3, ...
when each json looks like {"a":"something", "b":"something", "c":"something"}
最简单的方法是通过用[
和]
封装它来使文件内容有效JSON,这样它就成了一个dicts列表,从列表中删除最后一项后,你可以将它转储回一个字符串然后删除它和最后的字符,将是[
和]
,您的原始文本文件不需要:
import json
with open('file.txt', 'r') as r, open('newfile.txt', 'w') as w:
w.write(json.dumps(json.loads('[%s]' % r.read())[:-1])[1:-1])
由于您只希望从文件中删除最后一个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()