(キャラクターI/ O)の代わりに(ブロックI/O)をgetline
使う機能はありますか?fread
fgetc
を介してファイルを文字単位で読み取ると、パフォーマンスが低下しますfgetc
。fread
パフォーマンスを向上させるために、 の内部ループでブロック読み取り経由を使用できると考えていますgetline
。ただし、これにより、行末を超えて読み取るという望ましくない影響が生じる可能性があります。少なくとも、これにはgetline
、ファイルの「未読」部分を追跡するための の実装が必要です。これには、ANSI C FILE セマンティクスを超えた抽象化が必要です。これは私たちが自分たちで実装したいものではありません!
アプリケーションのプロファイリングを行いましたが、パフォーマンスの低下は、大きなファイルを 1 文字ずつ消費しているという事実に起因していますfgetc
。残りのオーバーヘッドは、比較すると実際には取るに足らないコストです。ファイルのすべての行を最初から最後まで常に順番に読み取り、読み取り中はファイル全体をロックできます。これにより、おそらくfread
ベースのgetline
実装が容易になります。
では、(キャラクターI/ O)の代わりに(ブロックI/O)をgetline
使う機能は存在するのでしょうか?そうなっていると確信していますが、そうでない場合、どのように実装すればよいのでしょうか?fread
fgetc
更新Paul Hsieh による便利な記事、 Handling User Input in Cを見つけました。これは にfgetc
基づくアプローチですが、代替案について興味深い議論があります (最初に がいかに悪いかgets
、次に について議論fgets
ます)。
一方、C プログラマー (経験者と見なされている人でも) からの一般的な反論は、代わりにfgets()を使用する必要があるというものです。もちろん、それ自体では、fgets()は実際にはユーザー入力自体を処理しません。奇妙な文字列終了条件 (\n または EOF に遭遇したとき、\0 に遭遇したとき) があることに加えて、バッファーが容量に達したときに終了するために選択されたメカニズムは、単純にfgets()操作を突然停止し、\0 で終了することです。したがって、ユーザー入力が事前に割り当てられたバッファーの長さを超える場合、fgets()部分的な結果を返します。この問題に対処するには、プログラマーにはいくつかの選択肢があります。1) 単純に切り捨てられたユーザー入力を処理します (入力を提供している間、入力が切り捨てられたことをユーザーにフィードバックする方法はありません) 2) 拡張可能な文字配列をシミュレートし、fgets()への連続呼び出しで入力します。 . 最初の解決策は、ほとんどの場合、可変長のユーザー入力に対して非常に貧弱な解決策です。これは、多くの通常のケースをキャプチャしようとするため、ほとんどの場合、バッファーが必然的に大きくなりすぎ、異常なケースでは小さすぎるためです。2 番目の解決策は、正しく実装するのが複雑になることを除けば問題ありません。どちらも'\0' に関するfgets の奇妙な動作を扱いません。
読者に残された演習: fgets()への呼び出しによって実際に読み取られたバイト数を決定するために、'\n' をスキャンするのと同じように、'\0' をスキップしてみてください。fgets()に渡されるサイズを超えない。ストリームの最後の行でこれが不十分な理由を説明してください。ftell() のどの弱点が、この問題に完全に対処するのを妨げていますか?
演習は読者にお任せします: fgets( )への呼び出しごとにゼロ以外の値でバッファ全体を上書きすることにより、 fgets()によって消費されるデータの長さを決定する問題を解決してください。
そのため、fgets()では、多くのコードを記述し、C ライブラリの残りの部分と矛盾する行終了条件に対処するか、任意のカットオフを設定するかを選択する必要があります。これで十分でない場合、何が残されるのでしょうか? scanf()は、分離できない方法で解析と読み取りを混合し、fread()は文字列の末尾を超えて読み取ります。要するに、C ライブラリには何も残されていません。fgetc()の上に直接基づいて独自にロールすることを余儀なくされています。それでは、試してみましょう。
それで、にgetline
基づくfgets
(そして入力を切り捨てない)関数は存在しますか?