> People focus myopically on the first aspect, but it's really the second that is the most important and most enduring
But something you can read and write to is not called a file, it is called a stream. It is no accident that Linux differentiates between “files” that you can write to at arbitrary places, or ones that are append-only.
> Certain files do not refer to disk files at all, but to I/O devices. [...] An effort is made to make these special files behave exactly the same way that ordinary disk files behave. This means that programs generally do not need to know whether they are reading or writing on some device or on a disk file.
> [...]
> Files are uniformly regarded as consisting of a stream of bytes; the system makes no assumptions as to their contents.
> [...]
> There is not distinction between "random" and sequential I/O. The read and write calls are sequential in that, for example, if you read 100 bytes from a file, the next read call will return bytes starting just after the last one read. It is however possible to move the read pointer around (by means of a "seek" call) so as to read the file in any order.
Though the abstraction is incomplete, the core concept in Unix is that "files" are opaque streams of bytes. Ancillary functions (e.g. seek, ioctl) are then layered atop the basic API to deal with files of different types as required.
Consider that before Unix most file APIs were record or block oriented. Unix unified the I/O model behind a single "file" abstraction--a stream of bytes. Unix stretched the term "file" to encompass a broader range of I/O tasks, but in turn also changed the treatment of traditional disk files in a way that made them look more like non-disk file I/O. This abstraction couldn't completely hide how I/O was serviced on the other side, but one can't criticize "everything is a file" without understanding the context of the time; nor can one full appreciate the value-add.
Also, something I hadn't notice before is how DMR emphasizes the synchronous nature of the API. Apparently many I/O APIs back then were asynchronous. Unix made the I/O model synchronous, but made it easy to create and juggle multiple processes so that you could implement various asynchronous models if you wanted. IOW, they flipped the default case. With the contemporary concern with intra-process I/O concurrency, that's an evolution we seem to be recapitulating.
But something you can read and write to is not called a file, it is called a stream. It is no accident that Linux differentiates between “files” that you can write to at arbitrary places, or ones that are append-only.