Вопрос-ответ

Find a line in a file and remove it

Найдите строку в файле и удалите ее

Я ищу небольшой фрагмент кода, который найдет строку в файле и удалит эту строку (не содержимое, а строку), но не смог найти. Так, например, у меня в файле есть следующее:

myFile.txt:

aaa
bbb
ccc
ddd

Нужно иметь функцию, подобную этой: public void removeLine(String lineContent), и если я пройду мимо
removeLine("bbb"), я получу файл, подобный этому:

myFile.txt:

aaa
ccc
ddd
Переведено автоматически
Ответ 1

Это решение может быть неоптимальным или красивым, но оно работает. Оно читает во входном файле построчно, записывая каждую строку во временный выходной файл. Всякий раз, когда программа обнаруживает строку, соответствующую тому, что вы ищете, она пропускает запись этой строки. Затем она переименовывает выходной файл. В примере я опустил обработку ошибок, закрытие программ чтения / записи и т.д. Я также предполагаю, что в строке, которую вы ищете, нет начальных или завершающих пробелов. Измените код вокруг trim() по мере необходимости, чтобы вы могли найти соответствие.

File inputFile = new File("myFile.txt");
File tempFile = new File("myTempFile.txt");

BufferedReader reader = new BufferedReader(new FileReader(inputFile));
BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile));

String lineToRemove = "bbb";
String currentLine;

while((currentLine = reader.readLine()) != null) {
// trim newline when comparing with lineToRemove
String trimmedLine = currentLine.trim();
if(trimmedLine.equals(lineToRemove)) continue;
writer.write(currentLine + System.getProperty("line.separator"));
}
writer.close();
reader.close();
boolean successful = tempFile.renameTo(inputFile);
Ответ 2
    public void removeLineFromFile(String file, String lineToRemove) {

try {

File inFile = new File(file);

if (!inFile.isFile()) {
System.out.println("Parameter is not an existing file");
return;
}

//Construct the new file that will later be renamed to the original filename.
File tempFile = new File(inFile.getAbsolutePath() + ".tmp");

BufferedReader br = new BufferedReader(new FileReader(file));
PrintWriter pw = new PrintWriter(new FileWriter(tempFile));

String line = null;

//Read from the original file and write to the new
//unless content matches data to be removed.
while ((line = br.readLine()) != null) {

if (!line.trim().equals(lineToRemove)) {

pw.println(line);
pw.flush();
}
}
pw.close();
br.close();

//Delete the original file
if (!inFile.delete()) {
System.out.println("Could not delete file");
return;
}

//Rename the new file to the filename the original file had.
if (!tempFile.renameTo(inFile))
System.out.println("Could not rename file");

}
catch (FileNotFoundException ex) {
ex.printStackTrace();
}
catch (IOException ex) {
ex.printStackTrace();
}
}

Это я нашел в Интернете.

Ответ 3

Вы хотите сделать что-то вроде следующего:


  • Откройте старый файл для чтения

  • Откройте новый (временный) файл для записи

  • Выполните итерацию по строкам в старом файле (возможно, используя BufferedReader)

    • Для каждой строки проверяйте, соответствует ли она тому, что вы должны удалить

    • Если она совпадает, ничего не делайте

    • Если она не совпадает, запишите ее во временный файл


  • Когда закончите, закройте оба файла

  • Удалите старый файл

  • Переименуйте временный файл в имя исходного файла

(Я не буду писать сам код, поскольку это выглядит как домашнее задание, но не стесняйтесь задавать другие вопросы по конкретным битам, с которыми у вас возникли проблемы)

Ответ 4

Итак, всякий раз, когда я слышу, как кто-то упоминает, что хочет отфильтровать текст, я сразу же думаю перейти к Streams (в основном потому, что есть метод с названиемfilter, который фильтрует именно так, как вам нужно). В другом ответе упоминается использование Streams с библиотекой Apache commons-io, но я подумал, что было бы целесообразно показать, как это можно сделать в стандартной Java 8. Вот простейшая форма:

public void removeLine(String lineContent) throws IOException
{
File file = new File("myFile.txt");
List<String> out = Files.lines(file.toPath())
.filter(line -> !line.contains(lineContent))
.collect(Collectors.toList());
Files.write(file.toPath(), out, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING);
}

Я думаю, там не так уж много объяснений, в основном Files.lines получает Stream<String> из строк файла, filter удаляет ненужные нам строки, затем collect помещает все строки нового файла в List. Затем мы записываем список поверх существующего файла с помощью Files.write, используя дополнительную опцию TRUNCATE таким образом, старое содержимое файла заменяется.

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

public void removeLine(String lineContent) throws IOException
{
File file = new File("myFile.txt");
File temp = new File("_temp_");
PrintWriter out = new PrintWriter(new FileWriter(temp));
Files.lines(file.toPath())
.filter(line -> !line.contains(lineContent))
.forEach(out::println);
out.flush();
out.close();
temp.renameTo(file);
}

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

java file