2012-05-13 3 views
2

fopen()でファイルオープンモードに問題があります。fopen()でオープンモードを選択する方法は?

私の場合、カーソルを自由に探したいと思っていますが、EOFを超えることもあります。さらに、既存のファイルを切り捨てるのではなく、追加することもできます。私はa+モードでファイルを開こうとしました。しかし、カーソルを自由に探すことはできません。カーソルがEOFを超えるたびに、指定した位置ではなく、新しい到着データがファイルの末尾に追加されます。一方、w+モードで開いている場合、既存のファイルは切り捨てられます。この問題に対する完璧な解決法はありますか?


UPDATE:明確に指定されていません

一つのポイントは、ファイルが常に存在しないかもしれないということです。その場合は新しいファイルを作成する必要があります。

実際、構成ファイルを処理したいとします。このように実装するのがよい習慣であるかどうかはわかりません。または、まず空の構成ファイルを配置する必要があります。したがって、ケースファイルが存在しないことを気にする必要はありませんか?

は、以下のコードスニペットです:

FILE *f = fopen(FILE_PATH, "wb+"); 
struct record r; 
if (f) { 
    if (fread((void *)&r, 1, sizeof(struct record), f) { 
     /* File exists, do the normal flow */ 
    } else { 
     if (feof(f)) { 
      /* File is newly created, do some initialization */ 
     } 
    } 
} else { 
    /* issue a warning */ 
} 
+1

ここに関連コードを掲載できますか? –

+0

私は興味があります..なぜあなたはEOFを越えて探求するか/書くことを目指していますか? – OrionRogue

+0

@OrionRogueファイルを使用してハードディスクをエミュレートします。データはチャンクで読み書きされます。最初にファイルが空で、データが 'EOF'の後ろに来る可能性があります。 –

答えて

5

あなたはまず、それがあると仮定して、その不在を扱う、二段階で、おそらく存在しないファイルに対処する必要があります:

if ((f = fopen(filename, "rb+") == 0) 
    f = fopen(filename, "wb+"); 
if (f == 0) 
    ...report error... 

"rb+"モードを開くに失敗します存在しないファイル(ただし、必要に応じて動作します)。ファイルが存在しない場合は、"wb+"が代わりに必要な処理を行います(ただし、ファイルは存在しても書き込める権限がないなど、まだ失敗する可能性があります)。二度目の試行でTOCTOU(Time of Check、Time of Use)攻撃を受けていないことを望む必要があります。

別のアプローチは、ファイルディスクリプタを開くために適切なフラグを持つopen()システムコールの3引数バージョンを使用して、ファイルディスクリプタから、ファイルストリームを作成するためにfdopen()を使用しています。

#include <fcntl.h> 

int fd; 
if ((fd = open(filename, O_RDRW | O_CREAT, 0644)) >= 0) 
    f = fdopen(fd, "rb+"); 

あなたが得ますフラグを使ってopen()をかなり正確に制御できます。

+0

通常、パーミッションビットとして '0666'を渡すことができ、ユーザがumaskを設定することを信頼します。これはまた、後で手動でファイルを 'chmod'する代わりに、ユーザが* umaskを設定できることを意味します。 –

+0

'fdopen'アプローチは唯一安全な方法です。 –

+0

@DietrichEppこれは有効な観察です - もしあなたが 'umask'が何であるか知っているとあなたのユーザを信じるならば。私は安全のために働いています。私はユーザーを信頼しません。私たちはもっと大きな文脈を持っていません。ファイルが存在する場合、そのパーミッションは変更されないので、誰もが誰もが自分の設定を編集したい場合、パブリックとグループの書き込み権限を設定できます。私は、他の人(他の人々)が自分の設定を安全なものとして変更することを認めていないので、0666の代わりに0644を意図的に使用しています。 –

2

モードがはっきりfopen(UNIX/Linuxの/ OS X上man 3 fopenを試してみてください)のために文書化されているファイル。

r+読み取りと書き込み用に開きます。ストリームはファイルの先頭に配置されます。

+1

ファイルが存在しない場合、' 'rb +' 'または' 'r +" 'モードは失敗します。その場合、TOCTOU(Time of Check、Time of Use)攻撃を受けていないことを望み、 '' wb + ''または' 'w +" 'で戻って再試行しなければなりません。 –

+0

POSIXに "存在する場合は変更する"、それ以外の場合は空の "セマンティクスを作成する場合は、' fopen'は役に立ちません。 'open'と' fdopen'が必要です。 –

-1

こんにちは、あなたはfseek関数によって読み書きが「W +」を使用することができ、私はそれを読んで、最初のファイルと各データ間隔にいくつかのバイトを作るためにfseekを使用するようにデータを書き込み、小さなデモプログラムを書き、:

#include <stdio.h> 
#include <unistd.h> 

#define FILE_PATH "seek_test.txt" 
#define STEP_SIZE 64 

void set_data(FILE* fp) 
{ 
    int i = 0; 
    fseek(fp, 0, SEEK_SET); 

    for (; i < 20; ++i) 
    { 
     fprintf(fp, "%d", i); 
     fseek(fp, STEP_SIZE, SEEK_CUR); 
    } 
} 

void get_data(FILE* fp) 
{ 
    int i = 0; 
    fseek(fp, 0, SEEK_SET); 

    for (; i < 20; ++i) 
    { 
     fscanf(fp, "%d", &i); 
     fprintf(stderr, "Cur Step: %5ld, value = %4d\n", i * STEP_SIZE, i); 
     fseek(fp, STEP_SIZE, SEEK_CUR); 
    } 
} 

int main(int argc, char* argv[]) 
{ 
    FILE* fp = fopen(FILE_PATH, "w+"); 
    if (fp == NULL) 
    { 
     printf("fopen Error\n"); 
     exit(0); 
    } 

    set_data(fp); 
    get_data(fp); 

    return 0; 
} 

===============================結果は以下の通り:

のCURステップ:0、値を= 0

Curステップ:64、値= 1

たCurステップ:128、値=

のCURステップ2:192、値=

のCURステップ3:256、値= 4

のCURステップ:320、値= 5

たCurステップ:384、値=

のCURステップ6:448、値= 7

のCURステップ:512、値= 8

のCURステップ:576、値= 9

のCURステップ:640、値= 10

のCURステップ:704、値= 11

のCURステップ:768、値= 12

CURステップ:832、値= 13

CURステップ:896、値= 14

CURステップ:960、値= 15

のCURステップ:1024、値=ステップ16

たCur:1088、値=

のCURステップ17:1152値=

のCURステップ18:1216の値= 19

=============

+0

ありがとう、まだすべての要件を満たすことはできません。私はついにジョナサンの答えを取る。 –

+0

これはファイルを切り捨てます。 – Barmar

関連する問題