Как записать перенаправленный вывод в файл внутри цикла в C? - PullRequest
1 голос
/ 12 сентября 2011

Я пишу программу на C для Unix, которая должна перенаправлять вывод в файл и записывать в нее какой-то текст каждую секунду в бесконечном цикле:

#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

int main(void) {
    int outDes = open("./output.txt", O_APPEND | O_WRONLY);
    dup2(outDes, 1);
    while(1) {
        printf("output text\n");
        sleep(1);
    }
}

Но она ничего не записывает в выходной файл.Я попытался изменить цикл while для for для 10 циклов и обнаружил, что он записывает все 10 строк в файл сразу после окончания серии.Это не очень хорошо для меня, хотя мне нужен бесконечный цикл.

Когда я не перенаправляю вывод, все нормально, и каждую секунду на терминале появляется новая строка.

Я также пытался поставить один

printf("text\n");

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

Может кто-нибудь объяснить мне, как это работает?

Ответы [ 2 ]

5 голосов
/ 12 сентября 2011
  1. Вы не проверяете возвращаемое значение open () и dup2 (). Если либо open (), либо dup2 () завершились неудачно, он ничего не запишет в output.txt.

    if (outDes < -1) {
        perror("open");
        return 1;
    }
    if (dup2(outDes, 1) == -1) {
        perror("dup2");
        return 1;
    }
    
  2. Потоки stdio буферизируются, и записи выполняются в памяти, прежде чем они будут выполнены в реальном описании файла.

    Попробуйте добавить fflush(stdout) после printf().

0 голосов
/ 12 сентября 2011

Вы сталкиваетесь с плохо документированной функцией DWIMmy во многих библиотеках Unix C. При первой записи в stdout или stderr библиотека проверяет базовый дескриптор файла (с isatty(3)). Если это (псевдо-) терминал, библиотека переводит ФАЙЛ в режим "буферизации строки", что означает, что она будет буферизовать ввод до тех пор, пока не будет записана новая строка, а затем сбросит все это в ОС. Но если файловый дескриптор является , а не терминалом, он переводит ФАЙЛ в режим «полностью буферизованный», где он буферизует что-то вроде BUFSIZ байтов вывода перед их сбросом и не обращает внимания на строку брейки.

Обычно это поведение, которое вы хотите, но если вы не хотите этого (как в этом случае), вы можете изменить его с помощью setvbuf(3). Эта функция (хотя не та, что я описал выше) является стандартом ISO C. Вот как ее использовать в вашем случае.

#include <stdio.h>
#include <unistd.h>

int
main(void)
{
    if (freopen("output.txt", "a", stdout)) {
        perror("freopen");
        return 1;
    }
    if (setvbuf(stdout, 0, _IOLBF, 0)) {
        perror("setvbuf");
        return 1;
    }

    for (;;) {
        puts("output text");
        sleep(1);
    }
    /* not reached */
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...