There are two similar implementations of async file IO.
NonBlockingFileIO in NIOPosix
FileSystem in NIOFileSystem
The implementations, on the first glance, look completely independent. Both of them basically utilize NIOThreadPool to run blocking syscalls. The APIs are slightly different though.
What are the subtle differences I missed? Is there any reason to keep two similar-ish implementations (apart from backwards compat)? Which one should applications default to?
Both are 100% different. NonBlockingFileIO is far older and was not designed with async/await in mind. FileSystem is a brand-new API that was designed from the ground up for async/await, and expects to be used in that environment.
We are keeping both because we have strict API stability guarantees, and there are existing successful users of NonBlockingFileIO. At the moment, NonBlockingFileIO is also far easier to use from a ChannelHandler than FileSystem, so that tends to be preferred.
If you are using async/await, prefer FileSystem. Otherwise, prefer NonBlockingFileIO.