74

stdinおよびstdout(そしておそらく私stderrがそこにいる間に)ファイルハンドルを再度開いて、ファイルへの、printf()またはputchar()ファイルputs()への今後の呼び出し、およびファイルへの今後の呼び出しgetc()などがファイルから行われるようにします。

1)標準の入出力/エラーを永久に失いたくない。プログラムの後半でそれらを再利用したいと思うかもしれません。

2)新しいファイルハンドルを開きたくないのは、これらのファイルハンドルを大量に渡すか、グローバル(シャダー)で渡す必要があるためです。

open()3)どうしようもないのならfork()、システムに依存する機能を使いたくない。

したがって、基本的に、これを行うのは機能しますか?

stdin = fopen("newin", "r");

そして、もしそうなら、どうすれば元の値をstdin取り戻すことができますか?に保存して、FILE *後で元に戻す必要がありますか?

4

8 に答える 8

94

freopen()を使用する理由 C89 仕様には、次のセクションのエンドノートの 1 つに回答があります<stdio.h>

116. 関数の主な用途は、標準テキスト ストリーム ( 、 、または) にfreopen関連付けられたファイルを変更することです。これらの識別子は、関数によって返される値が割り当てられる変更可能な左辺値である必要はありません。stderrstdinstdoutfopen

freopenはよく誤用されstdin = freopen("newin", "r", stdin);ます。これは より移植性がありませんfclose(stdin); stdin = fopen("newin", "r");。どちらの式も に割り当てようとしstdinますが、割り当て可能であるとは限りません。

使用する正しい方法freopenは、割り当てを省略することです。freopen("newin", "r", stdin);

于 2009-02-25T15:19:38.683 に答える
17

私はあなたがのようなものを探していると思いますfreopen()

于 2009-02-25T05:58:57.530 に答える
10

これは、Tim Post の方法の修正版です。/dev/stdout の代わりに /dev/tty を使用しました。stdout (/proc/self/fd/1 へのリンク) で動作しない理由がわかりません:

freopen("log.txt","w",stdout);
...
...
freopen("/dev/tty","w",stdout);

/dev/tty を使用すると、アプリが起動された端末に出力がリダイレクトされます。

この情報がお役に立てば幸いです。

于 2009-06-03T23:21:54.740 に答える
9

os 関数dup2()は、必要なものを提供する必要があります(正確に必要なものへの参照ではない場合)。

より具体的には、stdin ファイル記述子を別のファイル記述子に dup2() し、stdin で他のことを行い、必要なときにコピーして戻すことができます。

dup() 関数は、開いているファイル記述子を複製します。具体的には、3 番目の引数に 0 を指定して、F_DUPFD 定数コマンド値を使用して、fcntl() 関数によって提供されるサービスに代替インターフェースを提供します。複製されたファイル記述子は、元のファイル記述子とロックを共有します。

成功すると、dup() は元のファイル記述子と次の共通点を持つ新しいファイル記述子を返します。

  • 同じ開いているファイル (またはパイプ)
  • 同じファイル ポインター (両方のファイル記述子が 1 つのファイル ポインターを共有する)
  • 同じアクセス モード (読み取り、書き込み、または読み取り/書き込み)
于 2009-02-25T06:22:58.253 に答える
9
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() は同じ fd を保持する必要があり、新しいストリームをそれらに割り当てるだけです。

したがって、これが実際にやりたいことを行っていることを確認する良い方法は次のようになります。

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() の予想される動作だと思います。ご覧のとおり、まだ 3 つのファイル記述子 (および関連するストリーム) しか使用していません。

シェルがリダイレクトするものがないため、これはシェルのリダイレクトをオーバーライドします。ただし、おそらくパイプを壊すでしょう。プログラムがパイプ (FIFO ではなく、パイプ) のブロック側にいる場合に備えて、SIGPIPE のハンドラーを設定することをお勧めします。

したがって、./your_program --stdout /tmp/stdout.txt --stderr /tmp/stderr.txt は、freopen() を使用して簡単に実行でき、同じ実際のファイル記述子を維持できます。私が理解できないのは、一度変更したら元に戻す必要があるのはなぜですか?確かに、誰かがどちらかのオプションを渡した場合、プログラムが終了するまでそれを維持したいと思うでしょうか?

于 2009-02-25T15:31:53.270 に答える
3

それまでの間、stdout または stderr をリダイレクトして、これらすべてを実行する C ソース コード ライブラリがあります。しかし、クールな部分は、インターセプトされたストリームに必要な数のコールバック関数を割り当てることができるため、1 つのメッセージを複数の宛先、DB、テキスト ファイルなどに非常に簡単に送信できることです。

その上、stdout や stderr と同じように見えて動作する新しいストリームを作成するのが簡単になり、これらの新しいストリームを複数の場所にリダイレクトすることもできます。

*oogle で U-Streams C ライブラリを探してください。

于 2012-07-21T06:39:09.353 に答える
3

freopen簡単な部分を解決します。dup何も読んでおらず、やなどの POSIX システム コールを使用する意思がある場合、古い stdin を維持することは難しくありませんdup2。あなたがそれから読み始めたなら、すべての賭けはオフです.

この問題が発生するコンテキストを教えていただけますか?

stdin古いものを放棄しstdoutて使用できる状況に固執することをお勧めしますfreopen

于 2009-02-25T06:27:12.707 に答える
0

これは、最も簡単に利用でき、便利で便利な方法です。

freopen("dir","r",stdin);
于 2013-10-28T18:50:58.707 に答える