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

71

Скажем, у меня есть текстовый файл, полный псевдонимов, как я могу удалить определенный псевдоним из этого файла?

  • 1
    Попробуйте fileinput , как описано @j-f-sebastian JF-Себастьяне здесь . Это , кажется, позволяет вам строку за строкой работать через временный файл, все с простой for синтаксиса.
Теги:
file
input

13 ответов

113
Лучший ответ

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

Сначала откройте файл:

f = open("yourfile.txt","r")

Далее, получите все ваши строки из файла:

lines = f.readlines()

Теперь вы можете закрыть файл:

f.close()

И снова откройте его в режиме записи:

f = open("yourfile.txt","w")

Затем запишите строки, кроме строки, которую вы хотите удалить. Возможно, вы захотите изменить "\n" на любую строку, заканчивающую использование вашего файла.

for line in lines:
  if line!="nickname_to_delete"+"\n":
    f.write(line)

В конце закройте файл еще раз.

f.close()
  • 2
    почему мы должны открывать и закрывать его дважды?
  • 3
    @Ooker: Вы должны открыть файл дважды (и закрыть его между), потому что в первом режиме он «только для чтения», потому что вы просто читаете текущие строки в файле. Затем вы закрываете его и снова открываете в «режиме записи», где файл доступен для записи, и вы заменяете содержимое файла без строки, которую хотите удалить.
Показать ещё 6 комментариев
55

Решение этой проблемы только с одним открытым:

f = open("target.txt","r+")
d = f.readlines()
f.seek(0)
for i in d:
    if i != "line you want to remove...":
        f.write(i)
f.truncate()
f.close()

Это решение открывает файл в режиме r/w ( "r +" ) и использует поиск reset f-указателя, а затем усекает, чтобы удалить все после последней записи.

  • 2
    Это сработало очень хорошо для меня, так как я должен был также использовать lockfile (fcntl). Я не мог найти способ использовать fileinput вместе с fcntl.
  • 1
    Было бы неплохо увидеть некоторые побочные эффекты этого решения.
Показать ещё 1 комментарий
12

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

with open("yourfile.txt","r") as input:
    with open("newfile.txt","wb") as output: 
        for line in input:
            if line!="nickname_to_delete"+"\n":
                output.write(line)

Что это! В одном цикле и один вы можете сделать то же самое. Это будет намного быстрее.

  • 0
    Вместо использования обычного цикла for мы можем использовать выражение генератора. Таким образом, программа не будет загружать все строки из файла в память, что не является хорошей идеей в случае больших файлов. Он будет иметь только одну строку в памяти за раз. С генератором выражение для цикла будет выглядеть так: (output.write(line) for line in input if line!="nickname_to_delete"+"\n")
  • 4
    @ShriShinde Вы не читаете файл в память, когда зацикливаетесь на объекте файла, поэтому это решение работает идентично вашему предложению.
Показать ещё 2 комментария
4

Проблема с чтением строк в первом проходе и внесением изменений (удаление определенных строк) во втором проходе заключается в том, что если размеры файлов огромны, у вас закончится ОЗУ. Вместо этого лучший подход состоит в том, чтобы читать строки один за другим и записывать их в отдельный файл, исключая те, которые вам не нужны. Я использовал этот подход с файлами размером до 12-50 ГБ, а использование ОЗУ остается практически неизменным. Только циклы ЦП показывают, что процесс обработки продолжается.

  • 1
    Некоторый код был бы полезен.
3

Это "fork" основано на решении, представленном @Lother здесь, которое, я считаю, следует считать правильным ответом.

Для файла с таким содержимым:

$ cat file.txt 
1: october rust
2: november rain
3: december snow

Эта вилка от решения Lother работает нормально:

#!/usr/bin/python3.4

with open("file.txt","r+") as f:
    new_f = f.readlines()
    f.seek(0)
    for line in new_f:
        if "snow" not in line:
            f.write(line)
    f.truncate()

Основным преимуществом является использование with open, которые отбрасывают использование f.close(), а также способ, которым script оценивает, содержит ли строка строку.

  • 0
    Если f.seek (0) требуется?
  • 0
    @yifan Да, да. В противном случае вместо перезаписи файла вы добавляете файл к себе (без исключаемых строк).
2

Не удастся решить, если вы поместили целый файл в память, я знаю, что в наши дни у всех есть тонны памяти, но подумайте, есть ли в файле несколько ГБ журналов или что-то в этом роде.

Лучше всего скопировать его по строкам в новый файл, чем удалить первый или что-то подобное

1

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

Вот как я могу это сделать:

import, os, csv # and other imports you need
nicknames_to_delete = ['Nick', 'Stephen', 'Mark']

Я предполагаю, что nicknames.csv содержит такие данные, как:

Nick
Maria
James
Chris
Mario
Stephen
Isabella
Ahmed
Julia
Mark
...

Затем загрузите файл в список:

 nicknames = None
 with open("nicknames.csv") as sourceFile:
     nicknames = sourceFile.read().splitlines()

Затем перейдите к списку в соответствии с вашими входом для удаления:

for nick in nicknames_to_delete:
     try:
         if nick in nicknames:
             nicknames.pop(nicknames.index(nick))
         else:
             print(nick + " is not found in the file")
     except ValueError:
         pass

Наконец, запишите результат в файл:

with open("nicknames.csv", "a") as nicknamesFile:
    nicknamesFile.seek(0)
    nicknamesFile.truncate()
    nicknamesWriter = csv.writer(nicknamesFile)
    for name in nicknames:
        nicknamesWriter.writeRow([str(name)])
nicknamesFile.close()
1

Если вы используете Linux, вы можете попробовать следующий подход.
Предположим, у вас есть текстовый файл с именем animal.txt:

$ cat animal.txt  
dog
pig
cat 
monkey         
elephant  

Удалить первую строку:

>>> import subprocess
>>> subprocess.call(['sed','-i','/.*dog.*/d','animal.txt']) 

то

$ cat animal.txt
pig
cat
monkey
elephant
  • 4
    Это решение не зависит от ОС, и, поскольку OP не указывал операционную систему, нет никаких причин размещать специфический для Linux ответ imo.
  • 0
    Любой, кто предлагает использовать подпроцесс для всего, что может быть сделано с помощью всего лишь python, получает отрицательный ответ! И +1 к @SteinarLima...... Я согласен
1

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

В некоторых конкретных случаях вы можете сделать лучше, чем это -

если все ваши элементы данных имеют одинаковую длину и не имеют определенного порядка, и вы знаете смещение того, с которым хотите избавиться, вы можете скопировать последний элемент над тем, который нужно удалить, и обрезать файл до последний элемент;

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

Это, вероятно, слишком много для коротких документов (что-то под 100 КБ?).

0

Сохраните строки в списке, затем удалите список, который вы хотите удалить, и напишите оставшиеся строки в новый файл

with open("file_name.txt", "r") as f:
    lines = f.readlines() 
    lines.remove("Line you want to delete\n")
    with open("new_file.txt", "w") as new_f:
        for line in lines:        
            new_f.write(line)
  • 0
    Когда вы даете ответ, предпочтительно дать какое-то объяснение, ПОЧЕМУ ваш ответ тот.
  • 0
    Если ваш файл не заканчивается новой строкой, этот код не удалит последнюю строку, даже если он содержит слово, которое вы хотите удалить.
0

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

main_file = open('data_base.txt').read()    # your main dataBase file
filter_file = open('filter_base.txt', 'w')
filter_file.write(main_file)
filter_file.close()
main_file = open('data_base.txt', 'w')
for line in open('filter_base'):
    if 'your data to delete' not in line:    # remove a specific string
        main_file.write(line)                # put all strings back to your db except deleted
    else: pass
main_file.close()

Надеюсь, вы найдете это полезным!:)

0

Мне понравился метод fileinput, как объяснялось в этом ответе: Удаление строки из текстового файла (python)

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

import fileinput
import sys
for line_number, line in enumerate(fileinput.input('file1.txt', inplace=1)):
    if len(line) > 1:
            sys.stdout.write(line)

Примечание. Пустые строки в моем случае имели длину 1

-1

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

  • 5
    (1) Вы имеете в виду tuple(f.read().split('\n')) ?? (2) «получить доступ к номеру строки вашего кортежа» и «присоединиться к вашему кортежу результата» звучит довольно загадочно; Фактический код Python может быть более понятным.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню