Перенаправление stdin и stdout из C
Я хочу открыть stdin
а также stdout
(и, возможно stderr
в то время как я на это) файловые ручки, так что будущие звонки printf()
или же putchar()
или же puts()
перейдет в файл, и будущие вызовы getc()
и такое придет из файла.
1) Я не хочу навсегда потерять стандартный ввод / вывод / ошибку. Я могу захотеть использовать их позже в программе.
2) Я не хочу открывать новые файловые дескрипторы, потому что эти файловые дескрипторы должны быть либо переданы много, либо глобально (дрожь).
3) Я не хочу использовать какие-либо open()
или же fork()
или другие системные функции, если я не могу помочь.
Итак, в основном, это работает, чтобы сделать это:
stdin = fopen("newin", "r");
И, если это так, как я могу получить первоначальное значение stdin
назад? Должен ли я хранить его в FILE *
и просто вернуть его позже?
8 ответов
Зачем использовать freopen()
? Спецификация C89 содержит ответ в одном из примечаний к разделу <stdio.h>
:
116. Основное использование
freopen
функция для изменения файла, связанного со стандартным текстовым потоком (stderr
,stdin
, или жеstdout
), так как эти идентификаторы не должны быть модифицируемыми lvalues, к которым возвращается значение, возвращаемоеfopen
функция может быть назначена.
freopen
обычно используется неправильно, например stdin = freopen("newin", "r", stdin);
, Это не более портативный, чем fclose(stdin); stdin = fopen("newin", "r");
, Оба выражения пытаются присвоить stdin
, который не гарантируется для назначения.
Правильный способ использования freopen
это, чтобы пропустить назначение: freopen("newin", "r", stdin);
Это модифицированная версия метода Тима Поста; Я использовал / dev / tty вместо /dev/stdout. Я не знаю, почему он не работает с stdout (это ссылка на /proc/self/fd/1):
freopen("log.txt","w",stdout);
...
...
freopen("/dev/tty","w",stdout);
С помощью / dev / tty вывод перенаправляется на терминал, с которого было запущено приложение.
Надеюсь, эта информация полезна.
freopen("/my/newstdin", "r", stdin);
freopen("/my/newstdout", "w", stdout);
freopen("/my/newstderr", "w", stderr);
... do your stuff
freopen("/dev/stdin", "r", stdin);
...
...
Это пика иглы на моем круглом квадратном отверстии-о-метре, чего вы пытаетесь достичь?
Редактировать:
Помните, что stdin, stdout и stderr являются файловыми дескрипторами 0, 1 и 2 для каждого вновь создаваемого процесса. freopen() должен сохранять те же файлы, просто назначать им новые потоки.
Итак, хороший способ убедиться, что это действительно делает то, что вы хотите, чтобы это было:
printf("Stdout is descriptor %d\n", fileno(stdout));
freopen("/tmp/newstdout", "w", stdout);
printf("Stdout is now /tmp/newstdout and hopefully still fd %d\n",
fileno(stdout));
freopen("/dev/stdout", "w", stdout);
printf("Now we put it back, hopefully its still fd %d\n",
fileno(stdout));
Я полагаю, что это ожидаемое поведение freopen(), как вы можете видеть, вы все еще используете только три файловых дескриптора (и связанные потоки).
Это переопределит любое перенаправление оболочки, так как не будет ничего для перенаправления оболочки. Тем не менее, это, вероятно, собирается сломать трубы. Возможно, вы захотите установить обработчик для SIGPIPE, если ваша программа окажется на блокирующем конце канала (не FIFO, канал).
Итак, ./your_program --stdout /tmp/stdout.txt --stderr /tmp/stderr.txt должен быть легко реализован с помощью freopen () и с теми же фактическими дескрипторами файлов. То, что я не понимаю, это то, почему вам нужно положить их обратно, когда меняете их? Конечно, если кто-то пропустит любой из этих вариантов, он захочет сохранить его до завершения программы?
Функция os dup2() должна предоставлять то, что вам нужно (если не ссылки на то, что вам нужно).
В частности, вы можете dup2() описатель файла stdin в другой дескриптор файла, делать другие вещи с stdin, а затем копировать его обратно, когда захотите.
Функция dup () дублирует дескриптор открытого файла. В частности, он предоставляет альтернативный интерфейс для службы, предоставляемой функцией fcntl (), используя постоянное значение команды F_DUPFD, с 0 в качестве третьего аргумента. Дублированный файловый дескриптор разделяет любые блокировки с оригиналом.
В случае успеха dup () возвращает новый дескриптор файла, который имеет следующие общие черты с оригиналом:
- Тот же открытый файл (или канал)
- Один и тот же файловый указатель (оба файловых дескриптора имеют один файловый указатель)
- Тот же режим доступа (чтение, запись или чтение / запись)
freopen
решает легкую часть. Сохранить старый stdin не сложно, если вы ничего не читали и готовы использовать системные вызовы POSIX, такие как dup
или же dup2
, Если вы начали читать с него, все ставки сняты.
Может быть, вы можете рассказать нам контекст, в котором возникает эта проблема?
Я бы посоветовал вам придерживаться ситуаций, когда вы готовы отказаться от старого stdin
а также stdout
и поэтому может использовать freopen
,
А пока есть библиотека исходного кода на C, которая сделает все это за вас, перенаправив stdout или stderr. Но самое интересное в том, что он позволяет назначать перехваченным потокам столько функций обратного вызова, сколько вы хотите, что позволяет очень легко отправлять одно сообщение нескольким получателям, БД, текстовому файлу и т. Д.
Кроме того, это делает тривиальным создание новых потоков, которые выглядят и ведут себя так же, как stdout и stderr, где вы также можете перенаправить эти новые потоки в несколько мест.
ищите библиотеку U-Streams C на *oogle.
Это наиболее удобный и удобный способ
freopen("dir","r",stdin);