Большинство системных и прикладных программ должно обеспечивать обмен информацией с файловой системой на жестких и гибких дисках, терминалами или другими периферийными устройствами, реализуя операции ввода-вывода данных. Cистема программирования C предусматривает два уровня организации операций ввода-вывода: базовый и буферизованный. Буферизованный ввод и вывод гарантируют мобильность исходного текста программы, но уступают базовому по эффективности объектного кода. Поэтому для проектирования универсальных прикладных программ, где важна переносимость программного обеспечения, целесообразно использование стандартных средств буферизованного ввода-вывода. Для системного программирования, где основным требованием является эффективность, характерна ориентация на базовый уровень ввода-вывода.
Базовый уровень обеспечивает прозрачную передачу данных между файлом и программой через системные вызовы ядра операционной системы. Они имеют уникальную реализацию для различных операционных сред и потому их код не является мобильным. Однако, в любой реализации они интерпретируют файл как последовательность байтов с прямым доступом, без какой-либо информационной структуры. Обработка файла на базовом уровне гарантирует чтение или запись требуемого для ввода-вывода числа байтов без промежуточной буферизации данных.
Буферизованный ввод-вывод образует программную надстройку над базовым уровнем, где файл интерпретируется как поток байтов, обработка которого осуществляется блоками через внутренний буфер в адресном пространстве сегмента данных программы. Поток может быть буферизован по строкам или по размеру блока данных ввода-вывода. При строчной буферизации каждая порция передаваемых данных ограничена символом перевода строки, но ее размер не превышает объем буфера потока. Этот способ буферизации применяется для оптимизации терминального интерфейса программы в потоках стандартного ввода и вывода. Файловые потоки обычно буферизуются по размеру блока. Передача данных в них происходит блоками фиксированного размера, который равен объему буфера потока. В обоих случаях буфер потока накапливает информацию для ввода-вывода, минимизируя число операций обмена, независимо от объема передачи данных. Программный обмен с буфером в потоке обеспечивают системные вызовы ввода-вывода базового уровня, в которых объем блока передаваемых данных согласован с размером буфера.
При выводе данные программы накапливаются в буфере потока. Содержимое буфера передается в файл, когда буфер полностью заполнен или получен символ перевода строки, если поток строчно-буферизован для отображения информации на терминале. В конце обработки потока передается остаток буфера. При вводе происходит считывание блока данных в буфер потока из файла или с терминала. Требуемый объем информации передается из буфера потока соответствующим структурам данных программы по запросу ввода. Очередной блок считывается в буфер потока, когда в буфере недостаточно данных для текущего запроса ввода.