So, whenever I hear someone mention that they want to filter out text, I immediately think to go to Streams (mainly because there is a method called filter
which filters exactly as you need it to). Another answer mentions using Stream
s with the Apache commons-io library, but I thought it would be worthwhile to show how this can be done in standard Java 8. Here is the simplest form:
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);
}
I think there isn't too much to explain there, basically Files.lines
gets a Stream<String>
of the lines of the file, filter
takes out the lines we don't want, then collect
puts all of the lines of the new file into a List
. We then write the list over top of the existing file with Files.write
, using the additional option TRUNCATE
so the old contents of the file are replaced.
Of course, this approach has the downside of loading every line into memory as they all get stored into a List
before being written back out. If we wanted to simply modify without storing, we would need to use some form of OutputStream
to write each new line to a file as it passes through the stream, like this:
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);
}
Not much has been changed in this example. Basically, instead of using collect
to gather the file contents into memory, we use forEach
so that each line that makes it through the filter
gets sent to the PrintWriter
to be written out to the file immediately and not stored. We have to save it to a temporary file, because we can't overwrite the existing file at the same time as we are still reading from it, so then at the end, we rename the temp file to replace the existing file.