0

ファイルを1行ずつ読みたいのですが。正常にfgets()動作していますが、渡したバッファサイズよりも行が長い場合はどうすればよいfgets()ですか?さらに、fgets()Unicodeに対応していないようで、UTF-8ファイルを許可したいので、行末を見逃してファイル全体を読み取る可能性があります。

それから私は私が使うだろうと思いgetline()ました。ただし、私はMac OS Xを使用しており、getline()で指定されていますが/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk/usr/include/stdio.h、ではない/usr/include/stdioためgcc、シェルで見つかりません。そして、それは明らかに特に移植性がありません、そして私が開発しているライブラリが一般的に役立つことを望みます。

では、Cでファイルを1行ずつ読み取るための最良の方法は何でしょうか。

4

2 に答える 2

1

まず第一に、U+2028のような非標準のラインターミネータについて心配する必要はほとんどありません。通常のテキストファイルにはそれらが含まれているとは思われず、通常のテキストファイルを読み取る既存のソフトウェアの圧倒的多数はそれらをサポートしていません。どちらがglibcで利用可能であるが、MacOSのlibcでは利用できないとおっしゃっていますが、そのような派手なラインターミネータをサポートしていgetline()たとしたら、私は驚きます。getline()LF(U + 000A)と、おそらくCR + LF(U + 000D U + 000A)をサポートするだけで、ほぼ確実に回避できます。そのために、UTF-8を気にする必要はありません。これがUTF-8のASCII互換性の美しさであり、仕様によるものです。

渡すバッファよりも長いサポートラインについては、fgets()fgetsの周りに少し追加のロジックを使用してこれを行うことができます。擬似コードの場合:

while true {
    fgets(buffer, size, stream);
    dynamically_allocated_string = strdup(buffer);
    while the last char (before the terminating NUL) in the buffer is not '\n' {
        concatenate the contents of buffer to the dynamically allocated string
        /* the current line is not finished. read more of it */
        fgets(buffer, size, stream);
    }
    process the whole line, as found in the dynamically allocated string
}

/etc/passwdしかし、繰り返しになりますが、システム構成ファイルを解析するソフトウェアから(一部の)スクリプト言語まで、それを気にしないソフトウェアが本当にたくさんあることに気付くと思います。ユースケースによっては、「十分な大きさの」バッファ(たとえば、4096バイト)を使用して、それより長い行をサポートしないことを宣言するだけで十分な場合があります。これをセキュリティ機能と呼ぶこともできます(行の長さの制限は、細工された入力ファイルからのリソース枯渇攻撃に対する保護です)。

于 2013-01-15T18:37:43.347 に答える
0

この回答に基づいて、私が思いついたのは次のとおりです。

#define LINE_BUF_SIZE 1024

char * getline_from(FILE *fp) {
    char * line = malloc(LINE_BUF_SIZE), * linep = line;
    size_t lenmax = LINE_BUF_SIZE, len = lenmax;
    int c;

    if(line == NULL)
        return NULL;

    for(;;) {
        c = fgetc(fp);
        if(c == EOF)
            break;

        if(--len == 0) {
            len = lenmax;
            char * linen = realloc(linep, lenmax *= 2);

            if(linen == NULL) {
                // Fail.
                free(linep);
                return NULL;
            }
            line = linen + (line - linep);
            linep = linen;
        }

        if((*line++ = c) == '\n')
            break;
    }
    *line = '\0';
    return linep;
}

読むにはstdin

char *line;
while ( line = getline_from(stdin) ) {
    // do stuff
    free(line);
}

他のファイルを読み取るには、最初に次のコマンドで開きますfopen()

FILE *fp;
fp = fopen ( filename, "rb" );
if (!fp) {
    fprintf(stderr, "Cannot open %s: ", argv[1]);
    perror(NULL);
    exit(1);
}

char *line;
while ( line = getline_from(fp) ) {
    // do stuff
    free(line);
}

これは私にとって非常にうまく機能します。@paul-tomblin によって提案されfgets()た代替案を見たいのですが、今夜それを理解するエネルギーがありません。

于 2013-01-25T08:18:54.143 に答える