Эффективно удалите последние две строки файла чрезвычайно крупного текста

У меня есть очень большой файл (~400 ГБ), и я должен удалить последние 2 строки из него. Я пытался использовать sed, но это работало в течение многих часов, прежде чем я сдался. Есть ли быстрый способ сделать это или я застрявший с sed?

31
задан 17.04.2016, 01:04

9 ответов

Я не попробовал это на большом файле, чтобы видеть, как быстро это, но это должно быть довольно быстро.

Использовать сценарий для удаления строк из конца файла:

./shorten.py 2 large_file.txt

Это ищет в конец файла, проверки, чтобы удостовериться, что последний знак является новой строкой, затем читает каждый символ, по одному идущий назад, пока это не нашло три новых строки и усекает файл сразу после той точки. Изменение внесено на месте.

Править: Я добавил версию Python 2.4 внизу.

Вот версия для Python 2.5/2.6:

#!/usr/bin/env python2.5
from __future__ import with_statement
# also tested with Python 2.6

import os, sys

if len(sys.argv) != 3:
    print sys.argv[0] + ": Invalid number of arguments."
    print "Usage: " + sys.argv[0] + " linecount filename"
    print "to remove linecount lines from the end of the file"
    exit(2)

number = int(sys.argv[1])
file = sys.argv[2]
count = 0

with open(file,'r+b') as f:
    f.seek(0, os.SEEK_END)
    end = f.tell()
    while f.tell() > 0:
        f.seek(-1, os.SEEK_CUR)
        char = f.read(1)
        if char != '\n' and f.tell() == end:
            print "No change: file does not end with a newline"
            exit(1)
        if char == '\n':
            count += 1
        if count == number + 1:
            f.truncate()
            print "Removed " + str(number) + " lines from end of file"
            exit(0)
        f.seek(-1, os.SEEK_CUR)

if count < number + 1:
    print "No change: requested removal would leave empty file"
    exit(3)

Вот версия Python 3:

#!/usr/bin/env python3.0

import os, sys

if len(sys.argv) != 3:
    print(sys.argv[0] + ": Invalid number of arguments.")
    print ("Usage: " + sys.argv[0] + " linecount filename")
    print ("to remove linecount lines from the end of the file")
    exit(2)

number = int(sys.argv[1])
file = sys.argv[2]
count = 0

with open(file,'r+b', buffering=0) as f:
    f.seek(0, os.SEEK_END)
    end = f.tell()
    while f.tell() > 0:
        f.seek(-1, os.SEEK_CUR)
        print(f.tell())
        char = f.read(1)
        if char != b'\n' and f.tell() == end:
            print ("No change: file does not end with a newline")
            exit(1)
        if char == b'\n':
            count += 1
        if count == number + 1:
            f.truncate()
            print ("Removed " + str(number) + " lines from end of file")
            exit(0)
        f.seek(-1, os.SEEK_CUR)

if count < number + 1:
    print("No change: requested removal would leave empty file")
    exit(3)

Вот версия Python 2.4:

#!/usr/bin/env python2.4

import sys

if len(sys.argv) != 3:
    print sys.argv[0] + ": Invalid number of arguments."
    print "Usage: " + sys.argv[0] + " linecount filename"
    print "to remove linecount lines from the end of the file"
    sys.exit(2)

number = int(sys.argv[1])
file = sys.argv[2]
count = 0
SEEK_CUR = 1
SEEK_END = 2

f = open(file,'r+b')
f.seek(0, SEEK_END)
end = f.tell()

while f.tell() > 0:
    f.seek(-1, SEEK_CUR)
    char = f.read(1)
    if char != '\n' and f.tell() == end:
        print "No change: file does not end with a newline"
        f.close()
        sys.exit(1)
    if char == '\n':
        count += 1
    if count == number + 1:
        f.truncate()
        print "Removed " + str(number) + " lines from end of file"
        f.close()
        sys.exit(0)
    f.seek(-1, SEEK_CUR)

if count < number + 1:
    print "No change: requested removal would leave empty file"
    f.close()
    sys.exit(3)
31
ответ дан 07.12.2019, 09:13

можно судить голову GNU

head -n -2 file
12
ответ дан 07.12.2019, 09:13

Я вижу, что мои Debian Сжать/системы тестирования (но не Lenny/stable) включают "усеченную" команду как часть "coreutils" пакета.

С ним Вы могли просто сделать что-то как

truncate --size=-160 myfile

удалить 160 байтов из конца файла (очевидно, необходимо выяснить точно, сколько символов необходимо удалить).

7
ответ дан 07.12.2019, 09:13

Проблема с sed состоит в том, что это - потоковый редактор - это обработает весь файл, даже если Вы только захотите сделать модификации около конца. Таким образом независимо от того, что, Вы создаете новый файл на 400 ГБ, линию за линией. У любого редактора, который воздействует на целый файл, вероятно, будет эта проблема.

Если Вы знаете количество строк, Вы могли бы использовать head, но снова это создает новый файл вместо того, чтобы изменить существующий на месте. Вы могли бы получить выигрыши в быстродействии от простоты действия, я предполагаю.

У Вас могла бы быть лучшая удача с помощью split повредить файл в мелкие кусочки, редактируя последний и затем использование cat для объединения их снова но я не уверен, будет ли это немного лучше. Я использовал бы количества байта, а не строки, иначе это, вероятно, будет не быстрее вообще - Вы все еще собираетесь быть созданием нового файла на 400 ГБ.

6
ответ дан 07.12.2019, 09:13

Попробуйте VIM... Я не уверен, добьется ли это цели или нет, поскольку я никогда не использовал его на таком большом файле, но я использовал его на меньших больших файлах в прошлом, дают ему попытку.

2
ответ дан 07.12.2019, 09:13

Какой файл и в какой формат? Может быть легче использовать что-то как Perl, зависящий от того, какой файл это - текст, графика, двоичный файл? Как это отформатировано - CSV, TSV...

1
ответ дан 07.12.2019, 09:13

Если Вы знаете, размер файла к байту (400000000160 говорят), и Вы знаете, что необходимо удалить точно 160 символов для разделения последних двух строк, то что-то как

dd if=originalfile of=truncatedfile ibs=1 count=400000000000

должен добиться цели. Это были возрасты, так как я использовал dd в гневе хотя; я, кажется, помню, что дела идут быстрее при использовании большего размера блока, но можно ли сделать, который зависит от того, являются ли строки, которые Вы хотите отбросить, в хорошем несколькими.

dd имеет некоторые другие опции увеличить текстовые записи на фиксированный размер, который мог бы быть полезным как предварительная передача.

1
ответ дан 07.12.2019, 09:13

Если "усеченная" команда не доступна в Вашей системе (см. мой другой ответ), посмотрите на "человека 2 усеченных" для системного вызова для усечения файла к указанной длине.

Очевидно, необходимо знать, к какому количеству символов необходимо усечь файл (размер минус длина проблемы две строки; не забывайте считать любые cr/lf символы).

И сделайте резервное копирование файла перед попыткой этого!

1
ответ дан 07.12.2019, 09:13
#!/bin/sh

ed "$1" << HERE
$
d
d
w
HERE

изменения внесены на месте. Это более просто и более эффективно, чем сценарий Python.

0
ответ дан 07.12.2019, 09:13

Теги

Похожие вопросы