Я ищу небольшой фрагмент кода, который найдет строку в файле и удалит эту строку (не содержимое, а строку), но не смог найти. Так, например, у меня в файле есть следующее:
myFile.txt:
aaa bbb ccc ddd
Нужно иметь функцию, подобную этой: public void removeLine(String lineContent), и если я пройду мимо removeLine("bbb"), я получу файл, подобный этому:
myFile.txt:
aaa ccc ddd
Переведено автоматически
Ответ 1
Это решение может быть неоптимальным или красивым, но оно работает. Оно читает во входном файле построчно, записывая каждую строку во временный выходной файл. Всякий раз, когда программа обнаруживает строку, соответствующую тому, что вы ищете, она пропускает запись этой строки. Затем она переименовывает выходной файл. В примере я опустил обработку ошибок, закрытие программ чтения / записи и т.д. Я также предполагаю, что в строке, которую вы ищете, нет начальных или завершающих пробелов. Измените код вокруг trim() по мере необходимости, чтобы вы могли найти соответствие.
Выполните итерацию по строкам в старом файле (возможно, используя BufferedReader)
Для каждой строки проверяйте, соответствует ли она тому, что вы должны удалить
Если она совпадает, ничего не делайте
Если она не совпадает, запишите ее во временный файл
Когда закончите, закройте оба файла
Удалите старый файл
Переименуйте временный файл в имя исходного файла
(Я не буду писать сам код, поскольку это выглядит как домашнее задание, но не стесняйтесь задавать другие вопросы по конкретным битам, с которыми у вас возникли проблемы)
Ответ 4
Итак, всякий раз, когда я слышу, как кто-то упоминает, что хочет отфильтровать текст, я сразу же думаю перейти к Streams (в основном потому, что есть метод с названиемfilter, который фильтрует именно так, как вам нужно). В другом ответе упоминается использование Streams с библиотекой Apache commons-io, но я подумал, что было бы целесообразно показать, как это можно сделать в стандартной Java 8. Вот простейшая форма:
Я думаю, там не так уж много объяснений, в основном Files.lines получает Stream<String> из строк файла, filter удаляет ненужные нам строки, затем collect помещает все строки нового файла в List. Затем мы записываем список поверх существующего файла с помощью Files.write, используя дополнительную опцию TRUNCATE таким образом, старое содержимое файла заменяется.
Конечно, недостатком этого подхода является загрузка каждой строки в память, поскольку все они сохраняются в List перед обратной записью. Если бы мы хотели просто изменять без сохранения, нам нужно было бы использовать некоторую форму OutputStream для записи каждой новой строки в файл по мере прохождения через поток, вот так:
В этом примере мало что изменилось. По сути, вместо использования collect для сбора содержимого файла в памяти, мы используем forEach так, чтобы каждая строка, которая проходит через filter, отправлялась в PrintWriter для немедленной записи в файл, а не сохранения. Мы должны сохранить ее во временный файл, потому что мы не можем перезаписать существующий файл одновременно с чтением из него, поэтому в конце мы переименовываем временный файл, чтобы заменить существующий файл.