如何在不创建临时文件的情况下从文件'in-place'中删除行?



我为我编写的程序编写了3个单独的测试用例。不幸的是,我填写了我的硬盘驱动器,也许大约300 GB。我想从每个测试用例文件中取样,然后删除文件的其余部分。

我知道如何在不使用" readline"的情况下读取在不使用内存的情况线,从而释放存储空间。

这是否可以使用Python库?

编辑:取出sed,它创建一个临时文件

我想从每个测试用例文件中取样,然后删除文件的其余部分。

从顶部逐行读取行。写您要保留在文件开头的文章。将当前偏移量保持在文件中的结尾以及未读部件开始的位置。

如果复制的一块可能与目的地重叠;使用类似于memmove(fp+current_offset, fp+unread_offset, count)的算法:"从缓冲区的开头复制字节" 。副本之后:

current_offset += count
unread_offset += count

继续直到采集足够的样品,然后致电file.truncate(current_offset)在文件中的样本后删除所有内容。

例如,如果您想随机保留一半的行:

#!/usr/bin/env python
import random
with open('big-big.file', 'r+b') as file:
    current_offset = file.tell()
    while True:
        line = file.readline() # b'n'-separated lines
        if not line: # EOF
            break
        if random.random() < 0.5: # keep the line
            unread_offset = file.tell()
            file.seek(current_offset)
            file.write(line)
            current_offset = file.tell()
            file.seek(unread_offset)
    file.truncate(current_offset)

这是一种尝试使用mmap重写的文件。我不想填充我的硬盘驱动器,所以没有测试任何大型。它是一个可运行的例子,但是您需要将这些东西刻在我用于测试的前后。

这将文件的前50%写入新文件,然后将其修剪。不知道这是否是您想要的顺序!

import mmap
import shutil
import os
from glob import glob
files_to_trim = 'deleteme*'
fraction_to_keep = .5
blocksize = 128*1024
# make test file
open('deleteme1', 'w').writelines('all work and no play {}n'.format(i)
    for i in range(6))
open('deleteme2', 'w').writelines('all work and no play {}n'.format(i)
    for i in range(10,18))

with open('output', 'wb') as out:
    for filename in sorted(glob(files_to_trim)):
        st_size = os.stat(filename).st_size
        sample_size = int(st_size * fraction_to_keep)
        with open(filename, 'r+b') as infile:
            memfile = mmap.mmap(infile.fileno(), 0)
            # find next line ending
            need_newline = False
            count = memfile.find(b'n', sample_size)
            if count >= 0:
                count += 1 # account for n
            else:
                count = st_size
                need_newline = memfile[-1] == 'n'
            # copy blocks to outfile
            for rpos in range(0, count+blocksize-1, blocksize):
                out.write(memfile[rpos:min(rpos+blocksize, count)])
            if need_newline:
                out.write('n')
            # trim infile
            remaining = st_size - count
            memfile[:remaining] = memfile[count:]
            memfile.flush()
            memfile.close()
            infile.truncate(remaining)
            infile.flush()
# validate test file
print('deleteme1:')
print(open('deleteme1').read())
print('deleteme2:')
print(open('deleteme2').read())
print('output:')
print(open('output').read())

最新更新