Java 8 streams filter lines from CSV but retain first line

XtremeBaumer :

I want to remove lines from a CSV file which contain the wrong date. In the process the CSV file should retain the header line. All this I want to perform using java 8 streams.

At first I cam up with this:

try (Stream<String> linesUnfiltered = Files.lines(f.toPath(), StandardCharsets.UTF_8)) {
    Stream<String> firstLine = linesUnfiltered.limit(1);
    Stream<String> linesFiltered = linesUnfiltered
            .filter(e -> e.contains(sdfFileContent.format(fileDate)));
    Stream<String> result = Stream.concat(firstLine, linesFiltered);
    Files.write(f.toPath(), (Iterable<String>) result::iterator);
}

But this throws the exception java.lang.IllegalStateException: stream has already been operated upon or closed because linesUnfiltered is reused. The suggestion on the web is to use a Supplier<Stream<String>>, but my understanding is that the supplier would read the file for each supplier.get() call, which is not very efficient.

And thats why I am asking if there is another way which is more efficient that this? I am pretty certain that it should be possible to perform the two operations on the same stream...

EDIT:

It is NOT a duplicate as the first item should not be removed. It should only be excluded from the filtering process but still be available in the result stream

ernest_k :

You can use a reader and call its readLine method to consume the header, then filter on the result of lines() (after consuming the first line from the same reader):

try (BufferedReader reader = Files.newBufferedReader(f.toPath(), 
                                  StandardCharsets.UTF_8)) {

    Stream<String> firstLine = Stream.of(reader.readLine());
    Stream<String> linesFiltered = reader.lines()
            .filter(e -> e.contains(sdfFileContent.format(fileDate)));
    Stream<String> result = Stream.concat(firstLine, linesFiltered);

    ...

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=11566&siteId=1