5

私は、テキスト ファイルを開き、読み取り、変更するコードをいじっていました。簡単な(単純化された)例は次のとおりです。

#include <stdio.h>
int main()
{
    FILE * fp = fopen("test.txt", "r+");
    char line[100] = {'\0'};
    int count = 0;
    int ret_code = 0;
    while(!feof(fp)){
        fgets(line, 100, fp);
        // do some processing on line...
        count++;
        if(count == 4) {
          ret_code = fprintf(fp, "replaced this line\n");
          printf("ret code was %d\n", ret_code);
          perror("Error was: ");
        }
    }
    fclose(fp);
    return 0;
}

gcc (4.6.2) でコンパイルされた Linux では、このコードが実行され、ファイルの 5 行目が変更されます。Visual C++2010 でコンパイルされた Windows7 で実行されている同じコードが実行され、成功したと主張されます (19 文字のリターン コードが報告され、perror「エラーはありません」と表示されます) が、行の置換に失敗します。

Linux では、私のファイルには完全な権限があります。

-rw-rw-rw- 1 mike users 191 Feb 14 10:11 test.txt

そして、私が知る限り、Windowsでも同じです:

test.txt (右クリック) -> プロパティ -> セキュリティ
「許可」は、ユーザー、システム、および管理者の読み取りと書き込みにチェックされています。

Windows で MinGW の gcc を使用しても同じ結果が得られるので、それが Visual C++ の「機能」ではないことはわかっています。

明らかな何かが欠けていますか、それともエラーが発生せず、出力も出力されないという事実は、Windowsr+で withを使用することの文書化されていない「機能」にすぎませんか?fopen()


編集: Microsoft のサイト
でも、"r+" を読み書き用に開く必要がある書かれているようです。彼らはまた、次のメモを作成しました。

"r+"、"w+"、または "a+" アクセス タイプが指定されている場合、読み取りと書き込みの両方が許可されます (ファイルは "更新" のために開かれていると言われます)。ただし、読み取りと書き込みを切り替えるときは、間に fflush、fsetpos、fseek、または巻き戻し操作が必要です。必要に応じて、現在の位置を fsetpos または fseek 操作で指定できます。

だから私は試しました:

        ...
        if(count == 4) {
          fflush(fp);
          ret_code = fprintf(fp, "replaced this line\n");
          fflush(fp);
          printf("ret code was %d\n", ret_code);
          ...

無駄に。

4

2 に答える 2

3

Linuxfopen()のmanページによると:

読み取りと書き込みは、任意の順序で読み取り/書き込みストリームに混在させることができます。ANSI C では、入力操作でファイルの終わりが検出されない限り、ファイル ポジショニング関数が出力と入力の間に介入する必要があることに注意してください。(この条件が満たされない場合、読み取りは、最新以外の書き込みの結果を返すことが許可されます。) したがって、fseek(3) または fgetpos(3) を配置することをお勧めします (Linux では実際に必要な場合もあります)。 ) このようなストリームでの書き込み操作と読み取り操作の間の操作。この操作は、(fseek(..., 0L, SEEK_CUR) のように) 同期の副作用のために呼び出される明らかなノーオペレーションである可能性があります。

そのため、ファイルからの読み取りと書き込みを切り替えるときfseek()は、常に (たとえば)を呼び出す必要があります。fseek(..., 0, SEEK_CUR)

于 2013-02-14T16:05:05.617 に答える
3

入力後に出力を実行する前にfflush()、シーク操作を実行する必要があります。何かのようなもの:

fseek(fp, ftell(fp), SEEK_SET); // not fflush(fp);

C99 標準 (7.19.5.3/6 "The fopen 関数) から:

ファイルが更新モード (上記のモード引数値のリストの 2 番目または 3 番目の文字として「+」) で開かれると、関連するストリームで入力と出力の両方が実行される場合があります。ただし、fflush 関数またはファイル配置関数 (fseek、fsetpos、または巻き戻し) への呼び出しを介在させずに、出力の直後に入力を続けてはならず、ファイル配置への呼び出しを介在させずに、入力の直後に出力を続けてはなりません。入力操作がファイルの終わりに達しない限り、機能します。

于 2013-02-14T16:09:52.540 に答える