cp-14. ファイル処理
(C プログラミング入門)
URL: https://www.kkaneko.jp/pro/adp/index.html
1
金子邦彦
C言語によるファイルの読み書き操作、ファイル処理の基本
手順(オープン、読み込み、書き出し、クローズ)の理解。
【学習内容の構成】
1. ファイルのオープンとクローズ:fopen関数によるファ
イルポインタの取得とfclose関数による終了処理
2. 1行単位の読み込み:fgets関数を用いたファイルからの
テキスト読み込み
3. データの取り出し:sscanf関数による行内データの分割
と抽出
4. 1行単位の書き出し:fprintf関数を用いたファイルへのテ
キスト出力
5. オープンモード:読み込み用"r"と書き出し用"w"の使い
分け
• 前提:C言語の基本文法、配列、構造体、関数の理解
• 意義:外部データとの連携によるプログラムの実用性向上
2
アウトライン
例題1. 1行単位のファイル読み込み
ファイルからの読み込み
ファイルの終わり(EOF ともいう)
例題2.ファイルからのデータ読み込み
ファイル中のデータの取り出し
例題3. 1行単位のファイル書き出し
ファイルへの書き出し
例題4. 3行目を2回読み込む
ファイルのランダムアクセス
3
ファイル読み込み
ファイル
プログラム
•ファイルの中身は書き換わらな
い
4
ファイル書き出し
ファイル
プログラム
•ファイルの中身が書き換わる
•ファイルは伸び縮みすることが
ある
5
目標
• ファイルの読み書きを行うような、簡単なプログ
ラムを書けるようになる
• ファイルを扱う手順(オープン,読み込み,書
き出し,クローズ)を理解する
6
例題1.1行単位のファイル読み込み
• ファイルを読み込んで,ファイルの中身に行
番号を付けて表示するプログラムを作る.
• ファイルの読み込みでは,1行単位の読み込みを
行うために fgets 関数を使う
• ファイルのオープンを行うために fopen 関数を使
い,ファイルのクローズを行うために fclose 関数
を使う
7
#include <stdio.h>
#pragma warning(disable:4996)
int main()
{
char line[100];
int i = 1;
FILE *in_file;
in_file = fopen("d:¥¥input.txt", "r");
if ( in_file == NULL ) {
printf( "fopen() error" );
return 0;
}
while( fgets( line, 100, in_file ) != NULL ) {
printf( "[%d]%s", i, line );
i++;
}
fclose(in_file);
return 0;
}
ファイルポインタ変数の宣言
ファイルのオープン
(ファイルポインタが得
られる)
ファイルのクローズ
(ファイルポインタを使ってクローズする)
ファイルのオープンに
失敗したかを調べている
ファイルの終わりに達し
ていないかを調べている
ファイルの
1行読み込み
8
実行結果例
[1]アレンジメントの特質
[2]・空間を分割
[3]・分割された部分(フェイス)は,凸性を有する(従って
有界)か,
[4] 非有界な半空間
[5]・ボロノイ図を容易に導ける
[6]・単体に容易に分解できる
9
プログラムとデータ
メモリ
fgets( line, 100, in_file )
①
ファイルの
1行読み込み
line[0]
line[1]
line[2]
line[3]
line[4]
printf( "[%d]%s", i, line );
②
1行分の表示
10
プログラム実行順
in_file = fopen("d:¥¥input.txt", "r");
fgets( line, 100, in_file ) != NULL
Yes
No
fclose(in_file);
printf( "[%d]%s", i, line );
i++;
11
ファイルのオープンとクローズ
• ファイルのオープン
• ファイルの読み書きを行う前に、ファイルはオー
プンされねばらならい
• ファイルのクローズ
• ファイルの読み書きが終わったら,ファイルはク
ローズされねばならない
12
ファイルポインタ
• ファイルポインタ変数の宣言
例)FILE *in_file;
「in_file」という名前の付いたファイルポインタ変数を宣言
• ファイルのオープン
例)in_file = fopen("d:¥¥input.txt", "r");
ファイルのオープンを行うと,ファイルポインタが得られる
• ファイルのクローズ
fclose(in_file);
ファイルポインタを使って,ファイルのクローズを行う
オープンすべき
ファイル名
オープンモード
r : 読み込みの意味
w: 書き出しの意味
13
ファイルポインタ変数の働き
・現在のファイルのファイル位置指示子
(ファイルの読み書き位置)
・ファイルのオープンモード
など
14
fgets の意味
• ファイルの1行読み込み
• ファイルの一行分を読み込んで,末端の¥0を付ける
• ファイルには,行の終わりに,改行記号(¥n)が付い
ている(目には見えない)
• 読み込み先(文字の配列)のサイズが,ファイルの1
行の長さより長いときは,「残りの部分」は変化しな
い
文字の配列
ファイル
M a r k ¥n ¥0
改行記号
文字列の末端
変化しない部分
Mark¥n
15
fgets で「100」を書く理由
文字の配列
ファイル
¥0
文字列の末端
fgets( line, 100, in_file )
配列のサイズが100ならば,読み込める文字は99まで
(最後に必ず「¥0」が付く)
ファイルポインタ
変数名
読み込み先の
配列のサイズ
読み込み先の
配列の変数名
16
NULLの意味
• fopen 関数では「ファイルオープンの失敗」
例) fopen(“d:¥¥input.txt", "r")
if ( in_file == NULL ) {
• fgets 関数では「ファイルの終わり」
例) fgets( line, 100, in_file ) != NULL
17
• 次のような名簿ファイルを読み込んで,1列目
の氏名と,3列目の住所だけを表示するプログ
ラムを作る
• 各データは,空白文字で区切られる.
• 1列目の氏名と,3列目の住所を取り出すために
sscanf 関数を使う
金子邦彦 1200/01/01 福岡市東区箱崎 092-642-4068
○○×× 1300/12/31 福岡市東区貝塚 092-642-3883
●●■■ 800/05/31 福岡市東区香椎 092-642-3884
18
例題2.ファイルからのデータ読み込み
#include <stdio.h>
#pragma warning(disable:4996)
int main()
{
char line[100];
char name[100];
char birth[100];
char address[100];
FILE *in_file;
in_file = fopen("a=d:¥¥Book1.csv", "r");
if ( in_file == NULL ) {
printf( "fopen() error" );
return 0;
}
while( fgets( line, 100, in_file ) != NULL ) {
sscanf_s( line, "%s %s %s", name, birth, address );
printf( "name=%s, address=%s¥n", name, address );
}
fclose(in_file);
return 0;
}
ファイルポインタ変数の宣言
ファイルのオープン
(ファイルポインタが得
られる)
ファイルのクローズ
(ファイルポインタを使ってクローズする)
ファイルのオープンに
失敗したかを調べている
ファイルの終わりに達し
ていないかを調べている
ファイルの
1行読み込み
1列目,2列目,3列目の取り出し
19
実行結果例
name=金子邦彦, address=福岡市東区箱崎
name=○○××, address=福岡市東区貝塚
name=●●■■, address=福岡市東区香椎
20
プログラムとデータ
メモリ
fgets( line, 100, in_file )
①
ファイルの
1行読み込み
line[0]
line[1]
line[99]
sscanf( line, "%s %s %s", name, birth, address );
②
1行分の表示
データの取り出し
name birth address
③
printf( "name=%s, ...
21
プログラム実行順
in_file = fopen("d:¥¥Book1.csv", "r");
fgets( line, 100, in_file ) != NULL
Yes
No
fclose(in_file);
sscanf( line, "%s %s %s", name, birth, address );
printf( "name=%s, address=%s¥n", name, address );
22
sscanf 関数
line の中身を調べて,1列目,2列
目,
3列目のデータを name, birth,
address
に格納する
sscanf( line, "%s %s %s", name, birth, address );
○○×× 1300/12/31 福岡市東区貝塚 092-642-3883
1行分
1列目
2列目
3列目
4列目
23
例題3.1行単位のファイル書き出し
• 2つの浮動小数データを読み込んで,sin 関数
を使った計算を行い,計算結果をファイルに
書き出すプログラムを作る.
• 「0」と「0.1」を読み込むと,0, 0.1, … 1.9
について,sin関数を使った計算を繰り返す(繰り
返し回数は20回とする)
• ファイルの書き出すでは,1行単位の書き出しを
行うために fprintf 関数を使う
• 書き出されたファイルは,Microsoft Excel で読
み込み可能な形式であること
24
#include <stdio.h>
#include <math.h>
struct compute {
double start_x;
double step_x;
};
void input_data( struct compute *data )
{
printf( "start_x =" );
scanf( "%lf", &(data->start_x) );
printf( "step_x =" );
scanf( "%lf", &(data->step_x) );
}
start_x と step_x を
キーボードから読み込む関数
25
void output_result( struct compute *data, char *file_name )
{
double x;
double y;
int i;
FILE* fp;
fp = fopen( file_name, "w" );
for( i = 0; i < 20; i++ ) {
x = data->start_x + ( i * data->step_x );
y = sin( x );
printf( "x= %lf, y= %lf¥n", x, y );
fprintf( fp, "x=, %lf, y=, %lf¥n", x, y );
}
fclose( fp );
}
start_x と step_x を使って計算
を行い,結果をファイルに書き込む関数
26
int main()
{
struct compute data;
input_data( &data );
output_result( &data, "z:¥¥data.csv" );
return 0;
}
27
関数呼び出しの流れ
input_data 関数
void input_data( struct compute *data )
main 関数
int main()
input_data(&data
);
関数呼び出し
return;
戻り
output_result(&data,"z:¥¥data.csv"
);
関数呼び出し
output_result 関数
void output_result( struct compute *data, char *file_name )
return;
戻り
28
1行単位のファイル読み込み
の手順
ファイルのオープン
ファイルのクローズ
fprintf 等を使って,
ファイルの1行書き出し
終わりか?
Yes
No
29
テキストファイルの読み書き
• 読み込み
• fgets と sscanf を使って,1行単位で読み込み
• 書き出し
• fprintf を使って,1行単位で書き出し
30
オープンモード
• “r” モード
• 読み込みモード
• 引数fileで指定したファイルが存在しないか,読み
込み不可能な場合には,オープンすることができ
ない.
• “w” モード
• 書き出しモード
• 引数fileで指定したファイルが存在しない場合には,
ファイルが新たに作成される.ファイルがすでに
存在した場合,ファイル中のデータはすべて捨て
られる(ファイルの長さは0になる).
fopen( file_name, "w" );
ファイル名
(文字列)
オープンモード
(文字列)
31
課題1.ファイルのコピー
• ファイルをコピーするプログラムを作りなさい
• ファイルを1行単位で読み込んで,別のファイルに1行
単位で書き出すことを繰り返す.
• ファイルの読み込みでは,1行単位の読み込みを行う
ために fgets 関数を使う
• ファイルの書き出しでは,1行単位での書き出しを行
うために fprintf関数を使う
• 2つのファイルを扱うために,2つのファイルポイン
タ変数の宣言を行うこと
• 読み込むべきファイルは,Zドライブに事前に作成して
おくこと
32