High-level languages often expose stream-based I/O abstraction to the programmer, where blocking or non-blocking streams offer
write operations. (AFAIK, message-based I/O seems is usually an even higher-level abstraction built on top of streams.)
But at the low level, the communication between the CPU and the hardware devices uses interrupts, programmed (polled) I/O, or DMA.
How can all of them map well into the same stream I/O abstraction that (as far as I can tell) completely hides the difference between these very different low-level models? Are there any cases where a high-level developer who uses stream I/O abstraction should actually be concerned about the difference between interrupt-driven and programmed I/O?