I vastly prefer using the open, close, read and write system calls. They are actually extremely easy to work with, easier than stdio functions. No buffering unless you explicitly add it: when you write data out, you know it's been written. Sizes are always known so you can actually implement proper memory and string structures in C literally from the ground up. They just return a negated errno constant to signal errors which means there's no brain damage like thread local global errno variables anywhere in your code. It's such a good feeling.
Buffering is the only real reason to build on top of those system calls. I wrote a very simple read buffer for my language's parser. It just sort of appeared organically
during development. Haven't bothered to buffer writes.