Я не попробовал это на большом файле, чтобы видеть, как быстро это, но это должно быть довольно быстро.
Использовать сценарий для удаления строк из конца файла:
./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)
Я вижу, что мои Debian Сжать/системы тестирования (но не Lenny/stable) включают "усеченную" команду как часть "coreutils" пакета.
С ним Вы могли просто сделать что-то как
truncate --size=-160 myfile
удалить 160 байтов из конца файла (очевидно, необходимо выяснить точно, сколько символов необходимо удалить).
Проблема с sed состоит в том, что это - потоковый редактор - это обработает весь файл, даже если Вы только захотите сделать модификации около конца. Таким образом независимо от того, что, Вы создаете новый файл на 400 ГБ, линию за линией. У любого редактора, который воздействует на целый файл, вероятно, будет эта проблема.
Если Вы знаете количество строк, Вы могли бы использовать head
, но снова это создает новый файл вместо того, чтобы изменить существующий на месте. Вы могли бы получить выигрыши в быстродействии от простоты действия, я предполагаю.
У Вас могла бы быть лучшая удача с помощью split
повредить файл в мелкие кусочки, редактируя последний и затем использование cat
для объединения их снова но я не уверен, будет ли это немного лучше. Я использовал бы количества байта, а не строки, иначе это, вероятно, будет не быстрее вообще - Вы все еще собираетесь быть созданием нового файла на 400 ГБ.
Какой файл и в какой формат? Может быть легче использовать что-то как Perl, зависящий от того, какой файл это - текст, графика, двоичный файл? Как это отформатировано - CSV, TSV...
Если Вы знаете, размер файла к байту (400000000160 говорят), и Вы знаете, что необходимо удалить точно 160 символов для разделения последних двух строк, то что-то как
dd if=originalfile of=truncatedfile ibs=1 count=400000000000
должен добиться цели. Это были возрасты, так как я использовал dd в гневе хотя; я, кажется, помню, что дела идут быстрее при использовании большего размера блока, но можно ли сделать, который зависит от того, являются ли строки, которые Вы хотите отбросить, в хорошем несколькими.
dd имеет некоторые другие опции увеличить текстовые записи на фиксированный размер, который мог бы быть полезным как предварительная передача.
Если "усеченная" команда не доступна в Вашей системе (см. мой другой ответ), посмотрите на "человека 2 усеченных" для системного вызова для усечения файла к указанной длине.
Очевидно, необходимо знать, к какому количеству символов необходимо усечь файл (размер минус длина проблемы две строки; не забывайте считать любые cr/lf символы).
И сделайте резервное копирование файла перед попыткой этого!
#!/bin/sh ed "$1" << HERE $ d d w HERE
изменения внесены на месте. Это более просто и более эффективно, чем сценарий Python.