In understanding the two implementations and their pros/cons, I think it's useful to generalize here:
- Generalize from the file concept to consider really any acquired resource; and
- Generalize from what the operating system provides, to what's also provided by the programming language, libraries, or frameworks used.
As to why systems may use the first method...
The answer would similarly apply to why you may want to use a programming idiom like RAII. I.e. do you want to do your own life cycle management of the resource or do you want it done for you.
Sometimes when life cycle management is done for us (us as programmers), we may lose the ability to do things that we want (things which might otherwise be possible if we implement the life cycle management ourselves). Sometimes it's more important to be unable to possibly leak a resource than it is to be able to access every bell and whistle for it.
Take memory management in C++ for example. We can allocate memory from the system using new
or we can instead call std::make_shared
. The former however requires us to also call delete
(at the end of its use) if we want to ensure the memory isn't leaked. Meanwhile Java doesn't give the programmer direct access to allocating memory and instead employs garbage collection so that "programmers can be spared the burden of having to perform manual memory management".
As to examples of the first method...
Many Unix-like operating systems provide a programmatic interface to the syslog
facility. While it has open and close like analogies in openlog
and closelog
, calling these is optional. One can just simply call syslog
to start system logging text.
Standard input and output similarly is also managed for us. When a program starts up, it typically already has these concepts opened and available. When it exits, those streams will be closed for us (as necessary). Programs don't need to call fclose(stdout)
(nor something like fopen("/dev/console")
). Programs can just call fputs
or fgets
using stdout
or stdin
.