• ベストアンサー

C言語のファイル出力について

C言語のfprintfによるファイル出力について教えてください。 fprintfで、下記の例のように、上書きする行を指定することはできますでしょうか? 出力ファイルは.csv形式で、モードは問いません。 例:既に、sample.csvというファイルがあり、中身が、 0 0 0 1 1 1 2 2 2 とします。プログラムのfprintfで、3 3 3という出力を2行目に上書きし、 0 0 0 3 3 3 2 2 2 と変更する。 もし上記の方法をご存知でしたら、ご教授いただけましたら幸いです。 よろしくお願いいたします。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.3

単に指定の行を指定の文字列に書き換えてファイルに上書きします。 例) > ○○○.exe sample.csv 1 "3 3 3" #include <stdio.h> #include <stdlib.h> #include <sys/stat.h> #include <memory.h> #include <malloc.h> struct FileMemory { char* buffer; int bufferSize; int offset; }; FileMemory* loadFile( const char* fileName ) { FileMemory* memory = NULL; FILE* stream = fopen( fileName, "rb" ); if( !stream ) return NULL; /*ファイルサイズ取得*/ struct _stat buf; if( _stat( fileName, &buf ) ) { fclose( stream ); return NULL; } if( !buf.st_size ) { fclose( stream ); return NULL; } /*ファイルサイズ分アロケート*/ int bufferSize = buf.st_size; char* buffer = ( char* )malloc( bufferSize + 1 ); memset( buffer, 0, bufferSize + 1 ); /*メモリにファイルを展開*/ if( 1 != fread( buffer, bufferSize, 1, stream ) ) { free( buffer ); fclose( stream ); return NULL; } fclose( stream ); /*ファイルメモリをセット*/ memory = ( FileMemory* )malloc( sizeof( FileMemory ) ); memory->buffer = buffer; memory->bufferSize = bufferSize; memory->offset = 0; /*改行コードをヌル文字に置き換える*/ for( int ii = 0; ii < bufferSize; ii++ ) { if( 0x0D == memory->buffer[ ii ] || 0x0A == memory->buffer[ ii ] ) memory->buffer[ ii ] = '\0'; } return memory; } void unloadFile( FileMemory* memory ) { if( memory ) { if( memory->buffer ) free( memory->buffer ); free( memory ); } } char* getLine( FileMemory* memory ) { if( !memory ) return NULL; if( ( 0 > memory->offset ) || ( memory->bufferSize <= memory->offset ) ) return NULL; /*行の先頭アドレスを返す*/ char* ptr = &memory->buffer[ memory->offset ]; /*次の行の先頭アドレスまでズラしておく*/ int sep = 0; while( memory->offset < memory->bufferSize ) { if( 2 <= sep ) break; if( '\0' == memory->buffer[ memory->offset ] ) ++sep; else sep = 0; memory->offset++; } return ptr; } int main(int argc, char* argv[]) { if( 4 != argc ) return -1; const char* fileName = argv[ 1 ]; /*ファイル名*/ int lineNo = atoi( argv[ 2 ] ); /*差し替える行インデックス*/ const char* str = argv[ 3 ]; /*差し替える文字列*/ /*ファイルをメモリ上に展開する*/ FileMemory* memory = loadFile( fileName ); if( !memory ) return -1; /*書き込み用にファイルをオープン*/ FILE* stream = fopen( fileName, "w" ); if( !stream ) return -1; /*行ごとに文字列を取得する*/ char* ptr = getLine( memory ); while( ptr ) { /*指定の行は指定の文字列で置き換える*/ if( lineNo-- == 0 ) fputs( str, stream ); /*上記以外は読み取った行を出力する*/ else fputs( ptr, stream ); fputs( "\n", stream ); ptr = getLine( memory ); } fclose( stream ); unloadFile( memory ); return 0; }

Alpc38
質問者

お礼

ご回答、ありがとうございました。大変、参考になりました。

その他の回答 (2)

回答No.2

fseekというのを調べてみましょう。

Alpc38
質問者

お礼

ご回答、ありがとうございました。fseek、初めて知りました。

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.1

入れ替えの前後で、文字数がまったく一緒ならできないことも無いですが、一般的には、テキストエディタの挿入モードのような、「適当に前後を詰めたり空けたりする」ということはできません。 一旦、別な記憶領域(メモリが十分ならメモリ、足りないなら一時ファイル等)に全部読み込んでおいて、変更しながら元にファイルに上書きする、というのが常套手段だと思います。

Alpc38
質問者

お礼

ご回答、ありがとうございました。大変、勉強になりました。

関連するQ&A