kqueue cannot be used for async IO on files, either. Same problem.
EVFILT_READ Takes a descriptor as the identifier, and returns
whenever there is data available to read. The
behavior of the filter is slightly different
depending on the descriptor type.
Sockets
[Non-listen] socket descriptors return when there is
data to be read, subject to the SO_RCVLOWAT value
of the socket buffer.
Vnodes
Returns when the file pointer is not at the end
of file. data contains the offset from current
position to end of file, and may be negative.
There's aio(4), but support and APIs vary wildly across platforms.
The Unix async model based around fds and select was really only designed for sockets, and has been extended to socket-like objects (pipes/fifos). Linux has added support for some other sources in the form of e.g. signalfd(), eventfd(), timerfd_create(); the BSDs just added it all to kqueue/kevent. Neither supports async file operations in the fd model (basic operations like read/write; nor more complicated operations like syncing a range, renaming a file, creating a file, etc).