|
C++の壺・ファイル篇1
C++の基本テクニックのTipsです。ファイル篇1では、C言語のファイルの読み込みと書き出しの方法を扱います。オブジェクトを利用したC++のファイル入出力は2で扱います。
| ページ | 項 目 | 内 容 |
| ファイル篇1
| ・Cのファイル処理 | : FILE構造体、fopen関数、fclose関数 |
| ・入出力関数 | : fgets関数、fputs関数、fprintf関数、fscanf関数 |
| ・更新モード | : rewind関数 |
| ・バイナリモード | : テキストモードとバイナリモード |
| ファイル篇2
| ・C++のファイル処理 | : ifstreamクラス、ofstreamクラス、openメンバ、closeメンバ |
| ・入出力処理 | : putメンバ、getメンバ、is_openメンバ、getlineメンバ |
| ・モードフラグ | : オープンモードフラグ |
| ファイル篇3
| ・バイナリ・アクセス | : fwriteとfread関数 / writeとreadメンバ |
| ・ランダム・アクセス | : fseekとftell / fgetposとfsetpos / seekp,seekg,tellp,tellg |
| ・エラー/EOF検知 | : feofとferror関数 / perrorとclearerr関数 / iostateフラグ |

C言語では、ファイルを扱う時は、"ファイルポインタ" という特殊な型を利用します。これは、ファイルにアクセスした際、その時々のアクセス情報を格納する構造体(FILE構造体)で、ポインタ宣言をしてから使用します。
| @ ファイルポインタの宣言 | : FILE構造体 |
| A ファイルを開く | : fopen関数 |
| B データの入出力 | : 読み込み(fgets, fgetc, fscanf)/ 書き出し(fputs, fputc, fprintf) |
| C ファイルを閉じる | : fclose関数 |
また、ファイルポインタを使う時は必ず fopen関数で開き、使い終わったら fclose関数で閉じる必要があります。fopen と fclose 関数の仕様は次のようになっています。
| fopen function |
| ・書式 | : FILE *fopen(const char *file, const char *mode) |
| ・機能 | : ファイルを開く |
| ・引数 | : file...ファイル名、 mode...アクセスモード |
| ・戻り値 | : 成功時...FILE構造体へのポインタ, 失敗時...NULL |
| ・要件 | : stdio.h のインクルード |
| fclose function |
| ・書式 | : int fclose(FILE *fp) |
| ・機能 | : ファイルを閉じる |
| ・引数 | : fp...FILE構造体へのポインタ |
| ・戻り値 | : 成功時...0, 失敗時...EOF |
| ・要件 | : stdio.h のインクルード |
fopen関数の引数にあるアクセスモードでは、ファイルのアクセス制限を指定します。これには以下のようなものがあります。また、fclose関数の戻り値の EOF は、本来はファイルの終端 (End Of File) を表す値ですが、今回のようにエラー値としても用いられることがあります。
| モード | 機 能
| ファイルがある時 | ファイルがない時 |
| r
| 読み込み(read) | 正常処理 | エラー(NULL) |
| w
| 書き出し(write) | 既存データを破棄 | 新規作成 |
| a
| 追加書き出し(append) | 既存データに追加 | 新規作成 |
| r+
| 読み込みと書き出し | 正常処理 | エラー(NULL) |
| w+
| 読み込みと書き出し | 既存データを破棄 | 新規作成 |
| a+
| 読み込みと追加書き出し | 既存データに追加 | 新規作成 |
#include <stdio.h>
// Cのファイル処理の手順
void main()
{
FILE *fp; // ファイルポインタの宣言
fp = fopen("sample.txt", "w"); // ファイルを開く
... // ファイル入出力
fclose(fp); // ファイルを閉じる
}
実際にファイルの読み書きを行う関数には様々なものが用意されています。その中に、fputs と fgets関数があります。 fgets関数は、指定した文字数(バイト数)をファイルから読み出して変数に格納します。fgets関数を使用すると、ファイルポインタは次の文字へ移動しますので、連続して使用することにより、ファイルの中身すべてを読み取ることができます。一度の読み込みは、改行文字 ('\n') が現れるか、ファイルの終端に達するか、あるいは読み込んだ文字数が n -1 になるまで続きます。なお、取得した文字列には NULL文字が付加されます。 一方、fputs関数は、指定した文字列をまとめてファイルに書き出す機能を持ちます。
| fgets function |
| ・書式 | : | char *fgets(char *str, int n, FILE *fp) |
| ・機能 | : | 文字列を指定文字数分ファイルから読み込む |
| ・引数 | : | str...格納場所, n...最大文字数, fp...FILE構造体へのポインタ |
| ・戻り値 | : | 文字列へのポインタ(ファイル終端かエラー時はNULL) |
| ・要件 | : | stdio.h のインクルード |
| fputs function |
| ・書式 | : | int fputs( const char *str, FILE *fp) |
| ・機能 | : | 文字列をファイルへ書き出す |
| ・引数 | : | str...出力する文字列, fp...FILE構造体へのポインタ |
| ・戻り値 | : | 成功時...0以上、失敗時...EOF |
| ・要件 | : | stdio.h のインクルード |
#include <stdio.h>
#include <stdlib.h> // exit使用
#include <conio.h> // getch使用
// ファイルへの書き出し
void main()
{
char fname[256] = "sample.txt";
char s[256] = "Hello World !";
FILE *fp;
fp = fopen(fname, "w");
if (fp == NULL) {
printf("ファイルを開けません!");
exit(1); // プログラム終了
}
fputs(s, fp);
fclose(fp);
if (getch()) return 0;
}
|
#include <stdio.h>
#include <stdlib.h> // exit使用
#include <conio.h> // getch使用
// ファイルの読み込み
void main()
{
char fname[256] = "sample.txt";
char s[256];
FILE *fp;
if ((fp=fopen(fname,"r"))==NULL) {
printf("ファイルを開けません!");
exit(1); // プログラム終了
}
while (fgets(s, 256, fp) != NULL) {
printf("%s", s); // 画面出力
}
fclose(fp);
if (getch()) return 0;
}
|
ファイル入出力には、これ以外にも、fgetc (一文字づつ読み込み)、fputc (一文字づつ書き出し)、fscanf (書式付きで読込)、fprintf (書式付で書き出し)などがあります。いずれも、使用すると、ファイルポインタが移動します。
| fprintf function |
| ・書式 | : | int fprintf(FILE *fp, const char *format [ , arg, ... ] ) |
| ・機能 | : | 文字列に書式を付けてファイルに書き出す |
| ・引数 | : | fp...FILE構造体へのポインタ、format...書式付き文字列、arg...引数 |
| ・戻り値 | : | 出力したバイト数 (エラー時は負の値を返す) |
| ・要件 | : | stdio.h のインクルード |
| fscanf function |
| ・書式 | : | int fscanf(FILE *fp, const char *format [ , arg, ... ] ) |
| ・機能 | : | 文字列に書式を付けてファイルから読み込む |
| ・引数 | : | fp...FILE構造体へのポインタ、format...書式付き文字列、arg...引数 |
| ・戻り値 | : | 出力したバイト数 (エラー時・終端時は EOF を返す) |
| ・要件 | : | stdio.h のインクルード |
fprintf関数と fscanf関数で用いられる書式付文字列 (format) は、printf関数の仕様に準じています。以下に仕様の主要部分を掲載しておきます。fscanf の引数は格納場所を示すアドレスとなりますので注意してください。
| 【printf / scanf format spec】 |
| ・format |
%[flags][width][precision]['h' | 'l']type ([]は省略可) |
| ・flags | '-'...左詰め / '+'...符号付 / '0'...0詰め / ' '(空白)...正数に空白を付加 / '#'...typeが 'o' の時は 0を、'x' の時は 0xを、'f' 'e' の時は小数点を付加 |
| ・width | 桁数(文字数)を数字で指定 ('*' : 引数で指定) |
| ・precision | 小数点以下の桁数(精度)を '.' と数字で指定 ('*' : 引数で指定) |
| ・'h' or 'l' | 'h'...short型として解釈 / 'l'...long型として解釈 |
| ・type | 'd'...十進値 / 'o'...八進値 / 'x'...十六進値 / 'u'...符号なし十進値 / 'f'...浮動小数点(float, double) / 'e'...指数値 / 'p'...ポインタ(アドレス) / 'c'...文字(char) / 's'...文字列 / '%'...'%' 自身 |
ファイルのアクセスモードで、r+, w+ a+ など、"+" が付いているもの(更新モード)は読み書きの両方が可能ですが、どちらかの操作を行うと、ファイルポインタが移動している可能性があり、次に使用する時に思った位置に読み込み、または書き出しができません。そのため、操作を行う前に、ファイルポインタを先頭に戻しておく必要があります。これには、rewind関数を利用することができます。他にも、fflush、fseek, fsetpos などの関数を使用することができます。
| rewind function |
| ・書式 | : | void rewind(FILE *fp); |
| ・機能 | : | ファイルポインタを先頭に戻す (エラー情報とEOF情報もクリアする) |
| ・引数 | : | fp...FILE構造体へのポインタ |
| ・戻り値 | : | なし |
| ・要件 | : | stdio.h のインクルード |
#include <stdio.h>
#include <conio.h> // getch使用
// ファイルの更新モード
void main()
{
FILE *fp;
char fname[256] = "sample.txt";
char s1[100] = "Hello World !";
char s2[100] = "Hello C++ !!";
char s3[256];
fp = fopen(fname, "w+"); // ファイルを "w+"モード で開く
if (fp != NULL) {
fprintf(fp, "%s\n%s\n", s1, s2); // 改行を付けてファイルへ書き出し
rewind(fp); // ファイルポインタを先頭に戻す
while (fgets(s3, 256, fp) != NULL) {
printf("%s", s3); // ファイルを読み込んで画面出力
}
fclose(fp);
}
if (getch()) return 0;
}
Cのファイル操作では、特に指定がなければテキストモードでファイルを扱うことになります。それとは別に、バイナリモードというモードも存在します。両者の違いは次のようなものです。
| モード
| cr+lf の読み込み
| '\n' の書き出し
| '1a' の処理 |
| テキストモード | '\n' に自動変換 | cr+lf に自動変換 | ファイルの終端 |
| バイナリモード | そのまま読み込む | そのまま書き出し | そのまま処理 |
通常、ファイルでは改行は cr + lf (0d : キャリッジリターン + 0a : ラインフィード) で表現します。テキストモードでは、C言語の改行表現である '\n' を、読み書き時に自動的にこれらに変換します。一方、バイナリモードではこれらのコードをそのまま扱います。
| テキストモード | → | バイナリモード | |
| r, w, a
| →
| rb, wb, ab
| (読み / 書き / 追加 +バイナリモード) |
| r+
| →
| r+b, rb+
| (読み込み+更新+バイナリモード) |
| w+
| →
| w+b, wb+
| (書き出し+更新+バイナリモード) |
| a+
| →
| a+b, ab+
| (追加書き出し+更新+バイナリモード) |
バイナリモードにするには、アクセスモードに "b" を付加します。(バイナリモードの指定は、OS が Windows の時のみ有効です。)
|