42

Suppose I have a java.util.stream.Stream of objects with some nice toString method: What's the shortest/most elegant solution to write this stream to a file, one line per stream element?

For reading, there is the nice Files.lines method, so I thought there must be a symmetric method for writing to file, but could not find one. Files.write only takes an iterable.

knub
  • 3,892
  • 8
  • 38
  • 63
  • 1
    I can see there's a method [`Files#write(Path, Iterable extends CharSequence>, OpenOption ...)`](https://docs.oracle.com/javase/8/docs/api/java/nio/file/Files.html#write-java.nio.file.Path-java.lang.Iterable-java.nio.file.OpenOption...-) that may help you. – Luiggi Mendoza Aug 17 '15 at 15:35
  • Maybe create a FileOutputStream and then create a PrintStream? – redxef Aug 17 '15 at 15:36
  • @ downvoter: Care to explain? @LuiggiMendoza: Yeah, I saw that too and edited my question already. That one only takes an iterable. Yes, I can convert, but I do not want to. – knub Aug 17 '15 at 15:38

1 Answers1

65

Probably the shortest way is to use Files.write along with the trick which converts the Stream to the Iterable:

Files.write(Paths.get(filePath), (Iterable<String>)stream::iterator);

For example:

Files.write(Paths.get("/tmp/numbers.txt"),
     (Iterable<String>)IntStream.range(0, 5000).mapToObj(String::valueOf)::iterator);

If it looks too hackish, use more explicit approach:

try(PrintWriter pw = new PrintWriter(Files.newBufferedWriter(
                     Paths.get("/tmp/numbers.txt")))) {
    IntStream.range(0, 5000).mapToObj(String::valueOf).forEach(pw::println);
}

If you have stream of some custom objects, you can always add the .map(Object::toString) step to apply the toString() method.

Community
  • 1
  • 1
Tagir Valeev
  • 97,161
  • 19
  • 222
  • 334
  • So how exactly does that work? How is an `Iterator` cast to an `Iterable`? – knub Aug 18 '15 at 09:03
  • 4
    @knub, it's not an iterator, it's method reference to the `iterator()` method (I don't call the `iterator()` method, I create method reference instead). It's quite normal usage of method reference, which can be converted to the functional interface type. – Tagir Valeev Aug 18 '15 at 09:51
  • Slightly cleaner Iterable source = stream::iterator; Files.write(path, source); -- no casts, easier to grok what its doing at a glance – Scott Carey Aug 24 '20 at 22:16
  • 1
    To clarify why a `PrintWriter` is created here (and not just a `Writer`): The methods in `Writer` all throw a checked `IOException`, which makes them annoying to use in `forEach`. On the other hand, `PrintWriter.println` throws no exception. Nice trick. – rolve Feb 05 '21 at 18:52