Прежде всего, скажу, что я думаю, что у вас больше проблем с буферизацией, чем с эффективностью. Это распространенная проблема при первом обращении к пакету stdio
.
Во-вторых, лучшей (и самой простой) реализацией простого копира данных от ввода к выводу является следующий фрагмент (скопированный из первого издания K & R).
while((c = fgetc(input)) != EOF)
fputc(c, output);
(ну, не буквальная копия, так как там K & R использует stdin
и stdout
как FILE*
дескрипторы, и они используют более простые вызовы getchar();
и putchar(c);
.) Когда вы пытаетесь сделать лучше чем это, обычно вы принимаете некоторые ложные предположения, такие как ошибка отсутствия буферизации или количество системных вызовов.
stdio
выполняет полную буферизацию, когда стандартный вывод представляет собой канал (действительно, он выполняет полную буферизацию всегда, кроме случаев, когда файловый дескриптор дает true
для вызова функции isatty(3)
), поэтому вы В случае, если вы хотите увидеть вывод, как только он станет доступен, по крайней мере, не нужно буферизовать вывод (с чем-то вроде setbuf(out, NULL);
или fflush()
) вашего вывода в какой-то момент, так что он не получит буферизируется в выходных данных, пока вы ожидаете входных данных для получения дополнительных данных.
Кажется, что вы видите, что вывод для программы less(1)
не виден, потому что он буферизируется во внутренних компонентах вашей программы. И это именно то, что происходит ... предположим, что вы кормите свою программу (которая, несмотря на обработку отдельных символов, выполняет полную буферизацию), не получает никакого ввода, пока не будет заполнен полный входной буфер (BUFSIZ
символов) подал к нему. Затем в цикле выполняется много одиночных вызовов fgetc()
, а в цикле выполняется много вызовов fputc()
(ровно BUFSIZ
вызовов каждый), и буфер заполняется на выходе. Но этот буфер не записан, потому что для принудительного сброса нужен еще один символ. Таким образом, пока вы не получите первые два BUFSIZ
фрагмента данных, вы ничего не получите в less(1)
.
Простой и эффективный способ - проверить после fputc(c, out);
, является ли символ \n
, и сбросить вывод с fflush(out);
в этом случае, и поэтому вы будете записывать строку вывода за раз.
fputc(c, out);
if (c == '\n') fflush(out);
Если вы ничего не делаете, буферизация выполняется в BUFSIZ
блоках, и обычно, не раньше, чем у вас будет такое количество данных на выходной стороне. И всегда помните fclose()
вещей (ну, это обрабатывается stdio
), иначе вы можете потерять вывод в случае прерывания вашего процесса.
ИМХО код, который вы должны использовать:
while ((c = fgetc(input)) != EOF) {
fputc(c, output);
if (c == '\n') fflush(output);
}
fclose(input);
fclose(output);
для лучшей производительности, без ненужной блокировки выходных данных в буфере.
Кстати, выполнение fread()
и fwrite()
одного символа - пустая трата времени и способ усложнить ситуацию (и подвержен ошибкам). fwrite()
одного символа не исключает использование буферов, поэтому вы не получите большей производительности, чем fputc(c, output);
.
Кстати (бис), если вы хотите сделать свою собственную буферизацию, не вызывайте функции stdio
, просто используйте вызовы read(2)
и write(2)
в обычных дескрипторах системных файлов. Хороший подход:
int input_fd = fileno(input); /* input is your old FILE * given by popen() */
int output_fd = fileno(output);
while ((n = read(input_fd, your_buffer, sizeof your_buffer)) > 0) {
write(output_fd, your_buffer, n);
}
switch (n) {
case 0: /* we got EOF */
...
break;
default: /* we got an error */
fprintf(stderr, "error: read(): %s\n", strerror(errno));
...
break;
} /* switch */
но это разбудит вашу программу только тогда, когда буфер полностью заполнен данными, или данных больше нет.
Если вы хотите передать свои данные в less(1)
, как только у вас будет на одну строку меньше, вы можете полностью отключить входной буфер с помощью:
setbuf(input, NULL);
int c; /* int, never char, see manual page */
while((c == fgetc(input)) != EOF) {
putc(c, output);
if (c == '\n') fflush(output);
}
И вы получите less(1)
, работающий, как только вы создадите одну строку выходного текста.
Что именно вы пытаетесь сделать? (Это было бы неплохо знать, поскольку вы, похоже, заново изобретаете программу cat(1)
, но с ограниченной функциональностью)