1

In Java, I have a file contains lines like:

abc
cbd
CFG
...

I want to remove CFG from the file if any of the lines matchs a string, which could be 'cfg', 'Cfg', or other case insensitive variations.

If I read the file into a Set, how can I achieve this? It seems more feasible to do this by reading the file into a List.

user697911
  • 10,043
  • 25
  • 95
  • 169

3 Answers3

1

Something like this?

try (BufferedReader bf = new BufferedReader(new FileReader(new File("PATH TO FILE")));
     BufferedWriter bw = new bw(new FileWriter(new File("PATH TO NEW FILE")))) {
  bf.lines()
      .filter(line -> !line.equalsIgnoreCase("cfg"))
      .forEach(line -> {
        try {
          bw.write(line);
        } catch (IOException e) {
          e.printStackTrace();
        }
  });
}

The only ugly thing is the need for two trys because of not being allowed to throw exceptions from lambdas.

saml
  • 794
  • 1
  • 9
  • 20
1

The following is a "lambda version" of the required code. Thanks to @Sam for the important point about re-raising any suppressed PrintWriter IOException.

Path in_file = Paths.get("infile");
Path out_file = Paths.get("outfile");
try (PrintWriter pw = new PrintWriter(out_file.toFile())) {
    Files.lines(in_file)
         .filter(line -> !line.equalsIgnoreCase("cfg"))
         .forEach(pw::println);
    if (pw.checkError()) {
        throw new IOException("Exception(s) occurred in PrintWriter");
    }
}

If you need to modify the file in place, then writing to it while reading from it is somewhat more difficult. You could read it all into memory first.

Path path = new Path("filename");
List<String> lines = Files.lines(path)
                          .filter(line -> !line.equalsIgnoreCase("cfg"))
                          .collect(Collectors.toList());

try(PrintWriter pw = new PrintWriter(path.toFile())) {
    lines.forEach(pw::println);
    if (pw.checkError()) {
        throw new IOException("Exception(s) occurred in PrintWriter");
    }
}

And finally, just in case, a non-lambda solution for compatibility with Java 7:

Path in_file = Paths.get("infile");
Path out_file = Paths.get("outfile");
try (BufferReader reader = Files.newBufferedReader(in_file);
         PrintWriter pw = new PrintWriter(out_file.toFile())) {

    String line;
    while((line = reader.readline()) != null) {
        if (!line.equalsIgnoreCase("cfg")) {
            pw.println(line);
        }
    }
    if (pw.checkError()) {
        throw new IOException("Exception(s) occurred in PrintWriter");
    }
}
Community
  • 1
  • 1
AJNeufeld
  • 8,526
  • 1
  • 25
  • 44
  • Nice! I didn't know that! – saml Apr 06 '16 at 00:43
  • 1
    @Sam - Ya, handy that `PrintWriter`. Now if they only had a `.collect(toFile(path))` collector, this could be a "one-liner"! – AJNeufeld Apr 06 '16 at 00:49
  • 1
    Though I've just read about it some more and it literally swallows Exceptions. I think I would be happier if it threw a RuntimeException for production use so I at least end up something in a log if it's gone a bit wrong. – saml Apr 06 '16 at 00:52
  • @Sam - You can call `if (pw.checkError()) { throw new IOException("Stream had errors"); }` at the end of the `try { }` block. Perhaps not quite as informative, but really you just care that there was a problem, and where it occurred for the most part. – AJNeufeld Apr 06 '16 at 00:59
  • Yeh I realised that would have the be the compromise :) – saml Apr 06 '16 at 01:01
0

You can search for the string in the list and remove that using a position.

public List<String> removeItemInListIgnoreCase(List<String> items, String itemToRemove){
        if(CollectionUtils.isEmpty(items)) 
        return new ArrayList<String>();
        for(int i=0; i<items.size();i++) {
            if(items.get(i).equalsIgnoreCase(itemToRemove)) {
                items.remove(i);
            }
        }
        return items;
    }