Самый быстрый способ удалить строку из большого файла в Python

Я работаю с очень большим (~11GB) текстовым файлом в системе Linux. Я выполняю его через программу, которая проверяет файл на наличие ошибок. Как только ошибка найдена, я должен или зафиксировать строку или удалить строку полностью. И затем повторитесь...

В конечном счете, как только я доволен процессом, я автоматизирую его полностью. На данный момент однако давайте предположим, что я выполняю это вручную.

Что было бы самым быстрым (с точки зрения времени выполнения) способ удалить определенную строку из этого большого файла? Я думал о выполнении его в Python..., но буду открыт для других примеров. Строка могла бы быть где угодно в файле.

Если Python, примите следующий интерфейс:

def removeLine(filename, lineno):

Спасибо,

- aj

22
задан AJ. 24 February 2010 в 21:02
поделиться

8 ответов

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

def removeLine(filename, lineno):
    fro = open(filename, "rb")

    current_line = 0
    while current_line < lineno:
        fro.readline()
        current_line += 1

    seekpoint = fro.tell()
    frw = open(filename, "r+b")
    frw.seek(seekpoint, 0)

    # read the line we want to discard
    fro.readline()

    # now move the rest of the lines in the file 
    # one line back 
    chars = fro.readline()
    while chars:
        frw.writelines(chars)
        chars = fro.readline()

    fro.close()
    frw.truncate()
    frw.close()
13
ответ дан 29 November 2019 в 05:36
поделиться

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

import os
from mmap import mmap
def removeLine(filename, lineno):
    f=os.open(filename, os.O_RDWR)
    m=mmap(f,0)
    p=0
    for i in range(lineno-1):
        p=m.find('\n',p)+1
    q=m.find('\n',p)
    m[p:q] = ' '*(q-p)
    os.close(f)

Если другую программу можно изменить для вывода смещения файла вместо номера строки, вы можете назначьте смещение для p напрямую и обойдитесь без цикла for

7
ответ дан 29 November 2019 в 05:36
поделиться

Насколько Я знаю, вы не можете просто открыть текстовый файл с помощью Python и удалить строку. Вы должны создать новый файл и переместить в него все, кроме этой строки. Если вы знаете конкретную строку, вы должны сделать что-то вроде этого:

f = open('in.txt')
fo = open('out.txt','w')

ind = 1
for line in f:
    if ind != linenumtoremove:
        fo.write(line)
    ind += 1

f.close()
fo.close()

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

1
ответ дан 29 November 2019 в 05:36
поделиться

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

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

Если строки имеют фиксированную длину и вы хотите удалить определенные номера строк, вы можете использовать seek для перемещения указателя файла ... Я сомневаюсь, что вам так повезло.

1
ответ дан 29 November 2019 в 05:36
поделиться

Синтаксические анализаторы C++ трудно построить .

Я не могу говорить с опытом использования C++ грамматик ANTLR. Здесь я обсуждаю то, что я узнал, прочитав заметки, приложенные к той, которую я видел на сайте ANTLR; по существу автор произвёл неполную грамматику. И это было только для C++ 98. Это было некоторое время с тех пор, как я посмотрел; могут быть и другие.

Наш Набор средств обновления программного обеспечения DMS имеет надежный внешний интерфейс C++ .

Лексер обрабатывает все элементы для ANSI, GCC3, MS Visual Studio 2008, включая числа с плавающей точки большой точности и т.д.

[ПРАВКА: 12/2011. Теперь обрабатывает директивы C++ 11 и OpenMP]

[EDIT: 3/2015: Теперь обрабатывает C++ 14 в вариантах GCC и MS. Смотрите некоторые деревья синтаксического анализа здесь на SO ]

Наличие «просто» синтаксического анализатора на самом деле не очень полезно. Над «просто разбором» и за его пределами наш фронтэнд построит АСТ, построит точные таблицы символов (для C++ это сделать крайне сложно), выполнит функционально-локальный анализ потока, позволит осуществить программные преобразования и т. д. См. Жизнь после анализа .

[EDIT: 5/2019: Теперь обрабатывает C++ 17 в вариантах ANSI, GCC и MS. Полное разрешение имен и типов в единицах компиляции. Используется для автоматизации масштабного рефакторинга/разделения класса Бога между системами из 3000 единиц компиляции.]

-121--3199715-

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

-121--2809759-

Обновление: решение с использованием sed по запросу плаката в комментарии.

Чтобы удалить, например, вторую строку файла:

sed '2d' input.txt

Используйте переключатель -i для редактирования на месте. Предупреждение: это разрушительная операция. Сведения об автоматическом создании резервной копии см. в справке по этой команде.

1
ответ дан 29 November 2019 в 05:36
поделиться

@OP, если вы можете использовать awk, например, предполагая номер строки 10

$ awk 'NR!=10' file > newfile
0
ответ дан 29 November 2019 в 05:36
поделиться

Я думаю, здесь был задан несколько похожий, если не совсем тот же тип вопроса. Чтение (и запись) построчно выполняется медленно, но вы можете сразу прочитать более крупный кусок в памяти, пройти эту построчно, пропуская строки, которые вам не нужны, а затем записать это как единый фрагмент в новый файл. Повторяйте до тех пор, пока не будете готовы. Наконец, замените исходный файл новым.

Когда вы читаете фрагмент, вам нужно иметь дело с последней, потенциально неполной строкой, которую вы прочитали, и добавить ее к следующему фрагменту, который вы читаете.

0
ответ дан 29 November 2019 в 05:36
поделиться
def removeLine(filename, lineno):
    in = open(filename)
    out = open(filename + ".new", "w")
    for i, l in enumerate(in, 1):
        if i != lineno:
            out.write(l)
    in.close()
    out.close()
    os.rename(filename + ".new", filename)
0
ответ дан 29 November 2019 в 05:36
поделиться
Другие вопросы по тегам:

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