Oslofjord

String filePath = "foobar.txt"; try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) { reader.lines() .filter(line -> !line.startsWith("#")) .map(String::toLowerCase) .flatMap(line -> Stream.of(line.split(" "))) .forEach(System.out::println); }

reader.lines()

Stream<String>

"#"

generate()

Flowable<String> file = Flowable.generate( () -> new BufferedReader(new FileReader(filePath)), (reader, emitter) -> { final String line = reader.readLine(); if (line != null) { emitter.onNext(line); } else { emitter.onComplete(); } }, reader -> reader.close() );

generate()

BufferedReader

onNext()

generate()

Meet Flowable.using() operator

using()

Stream

Flowable

Stream

Iterator

Flowable.fromIterable(new Iterable<String>() { @Override public Iterator<String> iterator() { final BufferedReader reader = new BufferedReader(new FileReader(filePath)); final Stream<String> lines = reader.lines(); return lines.iterator(); } });

Flowable.<String>fromIterable(() -> { final BufferedReader reader = new BufferedReader(new FileReader(filePath)); final Stream<String> lines = reader.lines(); return lines.iterator(); });

BufferedReader

FileReader

using()

try-with-resources

Flowable.using( () -> new BufferedReader(new FileReader(filePath)), reader -> Flowable.fromIterable(() -> reader.lines().iterator()), reader -> reader.close() );

generate()

reader

Flowable

using()

BufferedReaders

using()

generate()

Flowable

Streaming XML files

<trkpt lat="52.23453" lon="21.01685"> <ele>116</ele> </trkpt> <trkpt lat="52.23405" lon="21.01711"> <ele>116</ele> </trkpt> <trkpt lat="52.23397" lon="21.0166"> <ele>116</ele> </trkpt>

<trkpt>

DOM/JAXB - everything must be loaded into memory and mapped to Java objects. Won't work for infinitely long files (or even very large ones)

SAX - a push-based library that invokes callbacks whenever it discovers XML tag opening or closing. Seems a bit better but can't possibly support backpressure - it's the library that decides when to invoke callbacks and there is no way of slowing it down

StAX - like SAX, but we must actively pull for data from XML file. This is essential to support backpressure - we decide when to read next chunk of data

XMLStreamReader

XMLStreamReader staxReader(String name) throws XMLStreamException { final InputStream inputStream = new BufferedInputStream(new FileInputStream(name)); return XMLInputFactory.newInstance().createXMLStreamReader(inputStream); }

<trkpt>

import lombok.Value; @Value class Trackpoint { private final BigDecimal lat; private final BigDecimal lon; } Trackpoint nextTrackpoint(XMLStreamReader r) { while (r.hasNext()) { int event = r.next(); switch (event) { case XMLStreamConstants.START_ELEMENT: if (r.getLocalName().equals("trkpt")) { return parseTrackpoint(r); } break; case XMLStreamConstants.END_ELEMENT: if (r.getLocalName().equals("gpx")) { return null; } break; } } return null; } Trackpoint parseTrackpoint(XMLStreamReader r) { return new Trackpoint( new BigDecimal(r.getAttributeValue("", "lat")), new BigDecimal(r.getAttributeValue("", "lon")) ); }

int

int

START_ELEMENT

END_ELEMENT

<trkpt>

</gpx>

null

Flowable<Trackpoint>

Flowable

Observable

Flowable<Trackpoint> trackpoints = generate( () -> staxReader("track.gpx"), this::pushNextTrackpoint, XMLStreamReader::close); void pushNextTrackpoint(XMLStreamReader reader, Emitter<Trackpoint> emitter) { final Trackpoint trkpt = nextTrackpoint(reader); if (trkpt != null) { emitter.onNext(trkpt); } else { emitter.onComplete(); } }

XMLStreamReader

XMLStreamReader