7

次の2つのファイルについて考えてみます。

file1.txt(Windows改行)

abc\r\n
def\r\n

file2.txt(Unix改行)

abc\n
def\n

file2.txtの場合、で取得した位置fgetposが正しくインクリメントされないことに気づきました。私はWindowsに取り組んでいます。

例を示しましょう。次のコード:

#include<cstdio>

void read(FILE *file)
{
    int c = fgetc(file);
    printf("%c (%d)\n", (char)c, c);

    fpos_t pos;
    fgetpos(file, &pos); // save the position
    c = fgetc(file);
    printf("%c (%d)\n", (char)c, c);

    fsetpos(file, &pos); // restore the position - should point to previous
    c = fgetc(file);     // character, which is not the case for file2.txt
    printf("%c (%d)\n", (char)c, c);
    c = fgetc(file);
    printf("%c (%d)\n", (char)c, c);
}

int main()
{
    FILE *file = fopen("file1.txt", "r");
    printf("file1:\n");
    read(file);
    fclose(file);

    file = fopen("file2.txt", "r");
    printf("\n\nfile2:\n");
    read(file);
    fclose(file);

    return 0;
}

そのような結果を与える:

file1:
a (97)
b (98)
b (98)
c (99)


file2:
a (97)
b (98)
  (-1)
  (-1)

file1.txtは期待どおりに機能しますが、file2.txtは奇妙な動作をします。何が問題なのかを説明するために、次のコードを試しました。

void read(FILE *file)
{
    int c;
    fpos_t pos;
    while (1)
    {
        fgetpos(file, &pos);
        printf("pos: %d ", (int)pos);
        c = fgetc(file);
        if (c == EOF) break;
        printf("c: %c (%d)\n", (char)c, c);
    }
}

int main()
{
    FILE *file = fopen("file1.txt", "r");
    printf("file1:\n");
    read(file);
    fclose(file);

    file = fopen("file2.txt", "r");
    printf("\n\nfile2:\n");
    read(file);
    fclose(file);

    return 0;
}

私はこの出力を得ました:

file1:
pos: 0 c: a (97)
pos: 1 c: b (98)
pos: 2 c: c (99)
pos: 3 c:
 (10)
pos: 5 c: d (100)
pos: 6 c: e (101)
pos: 7 c: f (102)
pos: 8 c:
 (10)
pos: 10

file2:
pos: 0 c: a (97) // something is going wrong here...
pos: -1 c: b (98)
pos: 0 c: c (99)
pos: 1 c:
 (10)
pos: 3 c: d (100)
pos: 4 c: e (101)
pos: 5 c: f (102)
pos: 6 c:
 (10)
pos: 8

fpos_t実装に依存しているので、それはコーダーによって解釈されることを意図していないことを私は知っています。ただし、上記の例ではfgetpos/の問題について説明していますfsetpos

改行シーケンスが、その文字に遭遇する前であっても、ファイルの内部位置にどのように影響する可能性がありますか?

4

2 に答える 2

3

この問題は、テキストモードで開かれているため、実装を混乱させる2番目のファイルが原因である可能性がありますが、要件に準拠していません。

標準では、

テキストストリームは、行に構成された文字の順序付けられたシーケンスであり、各行は0個以上の文字と終了する改行文字で構成されます

2番目のファイルストリームには、有効な改行文字が含まれていません(\r\n内部で改行文字に変換するために検索されるため)。その結果、実装は行の長さを正しく理解できず、その中で動き回ろうとすると絶望的に混乱する可能性があります。

さらに、

ホスト環境でテキストを表すためのさまざまな規則に準拠するために、入力および出力で文字を追加、変更、または削除する必要がある場合があります。

ライブラリは、呼び出しfgetc時にファイルから各バイトを読み取るだけでなく、ファイル全体(非常に小さい場合)をストリームのバッファに読み込んで操作することに注意してください。

于 2013-03-27T00:20:52.407 に答える
2

私はこれをteppicの答えのサポート情報として追加しています:

FILE*バイナリではなくテキストとして開かれたを処理する場合fgetpos()、VC ++ 11(VS 2012)の関数は、file2.txt次のようなコードになってしまう可能性があります(例としてはそうです)。

// ...

if (_osfile(fd) & FTEXT) {
        /* (1) If we're not at eof, simply copy _bufsiz
           onto rdcnt to get the # of untranslated
           chars read. (2) If we're at eof, we must
           look through the buffer expanding the '\n'
           chars one at a time. */

        // ...

        if (_lseeki64(fd, 0i64, SEEK_END) == filepos) {

            max = stream->_base + rdcnt;
            for (p = stream->_base; p < max; p++)
                if (*p == '\n')                     // <---
                    /* adjust for '\r' */           // <---
                    rdcnt++;                        // <---

// ...

\nバッファ内の任意の文字は、元々\r\n、データがバッファに読み込まれたときに正規化されたシーケンスであると想定しています。\rそのため、ファイルの以前の処理がバッファから削除されたと信じている(現在は欠落している)文字を説明しようとする場合があります。この特定の調整は、ファイルの終わりに近づいたときに発生します。\rただし、処理で削除されたバイトを説明するために、他の同様の調整がありますfgetpos()

于 2013-03-27T07:35:49.427 に答える