Буферизация ввода и вывода по умолчанию для файлов fopen'd? - PullRequest
7 голосов
/ 19 апреля 2010

Таким образом, поток FILE может иметь как входной, так и выходной буферы. Вы можете настроить выходной поток, используя setvbuf (я не знаю ни одного метода воспроизведения размера и поведения входного буфера).

Кроме того, по умолчанию используется буфер BUFSIZ (не уверен, что это POSIX или C). Очень ясно, что это означает для stdin / stdout / stderr, но каковы значения по умолчанию для вновь открытых файлов? Они буферизуются как для ввода, так и для вывода? Или, может быть, только один?

Если он буферизован, выводится ли по умолчанию выход в блочный или линейный режим?

РЕДАКТИРОВАТЬ: Я провел несколько тестов, чтобы увидеть, как ответ Джонатана Леффлера повлиял на программы реального мира. Кажется, что если вы читаете, то пишите. Запись приведет к тому, что неиспользованная часть входного буфера будет полностью отброшена. Фактически, будут некоторые поиски, которые сделаны, чтобы держать вещи в правильных смещениях файла. Я использовал эту простую тестовую программу:

/* input file contains "ABCDEFGHIJKLMNOPQRSTUVWXYZ" */
#include <stdio.h>
#include <stdlib.h>

int main() {

    FILE *f = fopen("test.txt", "r+b");
    char ch;
    fread(&ch, 1, 1, f);
    fwrite("test", 4, 1, f);
    fclose(f);
    return 0;
}

привел к следующим системным вызовам:

read(3, "ABCDEFGHIJKLMNOPQRSTUVWXYZ\n", 4096) = 27 // attempt to read 4096 chars, got 27
lseek(3, -26, SEEK_CUR)                 = 1        // at this point, I've done my write already, so forget the 26 chars I never asked for and seek to where I should be if we really just read one character...
write(3, "test", 4)                     = 4        // and write my test
close(3)                                = 0

Хотя это явно детали реализации, я нашел их очень интересными в том, как можно реализовать стандартную библиотеку. Спасибо Джонатану за твой проницательный ответ.

1 Ответ

6 голосов
/ 19 апреля 2010

Один файловый поток имеет один буфер. Если файл используется как для ввода, так и для вывода, то вы должны убедиться, что выполняете соответствующие операции (fseek () или эквиваленты) между операциями чтения и записи (или записи и чтения).

Поведение буферизации стандартных каналов зависит от платформы.

Как правило, stdout - это буферизованная строка, когда выход поступает на терминал. Однако, если стандартный вывод идет в файл или канал, а не в терминал, он обычно переключается на полную буферизацию.

Как правило, stderr является либо буферизованной строкой, либо небуферизованной, чтобы гарантировать, что сообщения об ошибках будут видны (например, даже в случае сбоя программы).

Как правило, stdin - это буферизованная строка; это означает, что у вас есть шанс отредактировать ваш ввод (возврат ошибок и т. д.). Вы бы редко это настраивали. Опять же, если входные данные поступают из файла (или канала), поведение может быть другим.

Вновь открытые файлы обычно полностью буферизуются. Конкретная реализация может изменить это на буферизацию строки, если устройство является терминалом.

Ваша предпосылка - что есть два буфера - неверна.


Раздел 7.19.3 C99, это говорит:

При запуске программы три текстовых потока предопределены и не требуют явного открытия - стандартный ввод (для чтения обычного ввода), стандартный вывод (для записи условный вывод) и стандартная ошибка (для записи диагностического вывода). Как изначально открыт, стандартный поток ошибок не полностью буферизован; стандартный ввод и стандарт выходные потоки полностью буферизуются тогда и только тогда, когда можно определить, что поток не относится к на интерактивное устройство.

Таким образом, как первоначально указывалось, stderr не буферизован или буферизованной строкой (он не полностью буферизован).

...