web-dev-qa-db-ja.com

Cでパイプから1行ずつ読み取る

パイプから出ている線をどのように分離できますか。パイプには次のテキストがあります。

HALLO:500\n
TEST:300\N
ADAD
ADAWFFA
AFAGAGAEG

値を変数に保存したいので、パイプから行を分離したいと思います。

これが私のcコードです:

#include <stdio.h>
#include <stdlib.h>

#define BUFFERSIZE    1

int main(int argc, char **argv){
    unsigned char     buffer[BUFFERSIZE];
    FILE                         *instream;
    int                            bytes_read=0;
    int                            buffer_size=0;


    buffer_size=sizeof(unsigned char)*BUFFERSIZE;
    /* open stdin for reading */
    instream=fopen("/dev/stdin","r");

    /* did it open? */
    if(instream!=NULL){
        /* read from stdin until it's end */
        while((bytes_read=fread(&buffer, buffer_size, 1, instream))==buffer_size){
            fprintf(stdout, "%c", buffer[0]);
        }
    }
    /* if any error occured, exit with an error message */
    else{
        fprintf(stderr, "ERROR opening stdin. aborting.\n");
        exit(1);
    }

    return(0);
}

これは、パイプから1行ずつ最適な読み取り方法ですか?

8
bladepit

これは通常、単にstdinからの読み取りと呼ばれます。プログラムは、入力がパイプ、リダイレクトされたファイル、またはキーボードのいずれであるかを気にする必要はありません。

freadは、バッファがいっぱいになるまで読み取るだけです。 fgetsを使用して行を読み取ります。

また、バッファサイズは、行を保持するのに十分な大きさである必要があります。小さな1回限りのプログラムの場合は、番号を選択するだけです。または、pretty-bigバッファを与える標準名BUFSIZがあります。どのくらいの大きさですか?十分な大きさ。本当に?恐らく。

fgetsは、文字列が最初にいっぱいにならない限り、文字列内の改行文字をコピーします。したがって、最後の文字をテストして、行が切り捨てられたかどうかを確認できます。妥当な入力があれば、それは起こりません。ただし、より堅牢なアプローチでは、より大きなバッファを割り当て、部分的な行をコピーして、もう一度fgetsを呼び出し、完全な行を取得しようとし続けます。

#include <stdio.h>

int main() {
    char buf[BUFSIZ];
    fgets(buf, sizeof buf, stdin);
    if (buf[strlen(buf)-1] == '\n') {
        // read full line
    } else {
        // line was truncated
    }
    return 0;
}

これにより、恐ろしいバッファオーバーフローの問題から保護されるまでの途中になります。 fgetsは、渡されたサイズを超えて書き込むことはありません。残りの半分は、前述のように、予想外に長い入力行から生じる可能性のある部分的な行で賢明なことをしています。

15
luser droog

別のオプションがあります(これが「適切な」方法かどうかは完全にはわかりません)-read関数によって読み取られたバイト数を使用します。この例では、stdinから読み取っていましたが、リダイレクトが行われたため、0のfdはファイル/パイプ/必要なものは何でもです。

  while ((nbytes=read(STDIN_FILENO, buffer, MAX_PIPE_SIZE)) > 0) {
    write(STDOUT_FILENO, buffer, nbytes);
  }
1
didinino