Писать одновременно в два потока - PullRequest
5 голосов
/ 25 июня 2009

Есть ли способ соединить два потока (или файловых дескриптора) вместе, чтобы запись в один поток также записывала во второй? (C, Linux)

Спасибо.

Ответы [ 5 ]

7 голосов
/ 25 июня 2009

Используйте funopen или fwopen и укажите свою собственную функцию записи, которая записывает несколько FILE* с.

Пример:

FILE *files[2] = ...;

FILE *f = fwopen((void *)files, my_writefn);

// ... use f as you like ...

int my_writefn(void *cookie, const char *data, int n) {
  FILE **files = (FILE **)cookie;
  fwrite(data, n, 1, files[0]);
  return fwrite(data, n, 1, files[1]);
}

(Обработка ошибок опущена.)

Обратите внимание, что funopen и fwopen являются BSD, а не в стандартном Linux. Я не знаю, есть ли Linux-совместимый эквивалент.

4 голосов
/ 25 июня 2009

Первое, что пришло мне в голову, это тоже «тройник». Итак, давайте скомбинируем C и оболочку с popen:

FILE * multi_out;

multi_out = popen( "tee file1.out > file2.out", "w");
/* error checks, actual work here */
pclose( multi_out);
/* error checks here */

Как фанат Unix, я предположил, что вы не пробуете это в Windows.

2 голосов
/ 30 сентября 2014

Пользователь laalto правильный, но в Linux искомая функция называется fopencookie. Исправление примера laalto для Linux приводит к:

int my_writefn(void *cookie, const char *data, int n) {
  FILE **files = (FILE **)cookie;
  fwrite(data, n, 1, files[0]);
  return fwrite(data, n, 1, files[1]);
}

int noop(void) { return 0; }
cookie_io_functions_t my_fns = {
  (void*) noop,
  (void*) my_writefn,
  (void*) noop,
  (void*) noop
};

FILE *files[2] = ...;

FILE *f = fopencookie((void *)files, "w", my_fns);

// ... use f as you like ...

Когда вы пишете в f, система выполнит вашу функцию my_writefn, передав ей данные, которые были переданы в fwrite. Чтобы упростить задачу, вы также можете изменить буферизацию для вашего файлового потока, чтобы она была ориентирована на строки:

setvbuf(f, NULL, _IOLBF, 0);

Это буферизует данные, передаваемые на fwrite, до тех пор, пока не будет выведен символ новой строки или пока не будут считаны какие-либо данные из любого потока, присоединенного к процессам (например, stdin). ПРИМЕЧАНИЕ: вы должны вызвать sevbuf после fopencookie, но до того, как какие-либо данные будут записаны в поток.

Я использую строковую буферизацию, потому что я обычно использую fopencookie для перенаправления stderr в системный журнал или через сетевой сокет, а обработка ориентированных на строки данных становится проще и эффективнее.

2 голосов
/ 25 июня 2009

Не уверен, что это то, что вы хотите, но 'tee' в Unix делает нечто подобное.

1 голос
/ 25 июня 2009

Вы можете реализовать нечто похожее на функциональность tee с помощью boost :: iostreams .

...