So I started to play with the Advent of Code and I would like to use the project reactor for this to find the solutions in a reactive way.
I have implemented a solutions that works partially but not quite how I want it. Because it can also read lines partially if there is no more space in the buffer.
The Input to run the following function you can find here: https://adventofcode.com/2022/day/1/input
public static Flux<String> getLocalInputForStackOverflow(String filePath) throws IOException {
Path dayPath = Path.of(filePath);
FileOutputStream resultDay = new FileOutputStream(basePath.resolve("result_day.txt").toFile());
return DataBufferUtils
.readAsynchronousFileChannel(
() -> AsynchronousFileChannel.open(dayPath),
new DefaultDataBufferFactory(),
64)
.map(DataBuffer::asInputStream)
.map(db -> {
try {
resultDay.write(db.readAllBytes());
resultDay.write("\n".getBytes());
return db;
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
})
.map(InputStreamReader::new)
.map(is ->new BufferedReader(is).lines())
.flatMap(Flux::fromStream);
}
The point of this function is to read the lines of the files in a reactive way.
I used the FileOutputStream
to write what I read into another file and the compare the resulted file with the original, because I noticed that some lines are only partially read if there is no more space in the buffer. So the try-catch .map()
can be ignored
My questions here would:
Is there a more optimal way to read files asynchronously in a Reactive way?
Is there a more optimal way to read a file asyncronously line by line with a limited buffer and make sure that only whole lines are read?
Workarounds that I've found are:
- Increased the buffer to read the whole file in 1 run -> Not optimal solution
- Use the following functions, but this raise a warning:
Possibly blocking call in non-blocking context could lead to thread starvation
public static Flux<String> getLocalInput1(int day ) throws IOException {
Path dayPath = getFilePath(day);
return Flux.using(() -> Files.lines(dayPath),
Flux::fromStream,
BaseStream::close);
}