C言語の基礎 - ファイル
ファイルを移動する
C言語で、ファイルを移動するには、stdio.hのrename関数を使用する。
rename関数は、oldが指すファイルをnewが指す文字列を名前とするファイルとして識別できるようにする関数である。
oldとnewがそれぞれ異なるディレクトリのファイル名を指している場合には、ファイルの移動が行われる。
rename関数は、ファイル名の変更が成功した場合は0、ファイル名の変更に失敗した場合は0以外の値を返す。
rename関数を呼び出す前に既にファイル名がnewであるファイルが存在している場合、rename関数の動作は処理系定義となるので注意する。
#include <stdio.h>
int rename (const char *old, const char *new);
以下の例では、rename関数を使用してファイルを移動している。
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char old[] = "./01/sample.txt";
char new[] = "./02/sample.txt";
if ( rename(old, new) == 0 )
{
printf("%sを%sに移動しました.\n", old, new);
}
else
{
fprintf(stderr, "%sの移動に失敗しました.\n", old);
}
return EXIT_SUCCESS;
}
ファイル名を変更する
C言語で、ファイルの名前を変更するには、stdio.hのrename関数を使用する。
rename関数は、oldが指すファイルをnewが指す文字列を名前とするファイルとして識別できるようにする関数である。
oldとnewが同じディレクトリのファイル名を指している場合は、ファイル名の変更が行われる。
rename関数は、ファイル名の変更が成功した場合は0、ファイル名の変更に失敗した場合は0以外の値を返す。
rename関数を呼び出す前に既にファイル名がnewであるファイルが存在している場合、rename関数の動作は処理系定義となるので注意する。
#include <stdio.h>
int rename (const char *old, const char *new);
以下の例では、rename関数を使用してファイル名を変更している。
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char old[] = "sample01.txt";
char new[] = "sample02.txt";
if ( rename(old, new) == 0 )
{
printf("%sの名前を%sに変更しました.\n", old, new);
}
else
{
fprintf(stderr, "%sのリネームに失敗しました.\n", old);
}
return EXIT_SUCCESS;
}
ファイルを削除する
C言語で、ファイルを削除するには、stdio.hのremove関数を使用する。
remove関数は、filenameが指すファイルを削除する関数である。
remove関数は、ファイルの削除が成功した場合は0、ファイルの削除に失敗した場合は0以外の値を返す。
既にファイルがオープンされている場合のremove関数の動作は、処理系定義になるので注意する。
#include <stdio.h>
int remove (const char *filename);
以下の例では、remove関数を使用してファイルを削除している。
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char filename[] = "sample.txt";
if ( remove(filename) == 0 )
{
printf("%sの削除が完了しました.\n", filename);
}
else
{
fprintf("stderr, %sの削除に失敗しました.\n", filename);
}
return EXIT_SUCCESS;
}
ファイルを開く
ファイルに対して読み書きを行うためには、まず、ファイルを開く必要がある。
C言語で、ファイルを開くには、stdio.hのfopen関数を使用する。
fopen関数は、filenameで指定されたファイルを開いて、そのファイルにストリームを結び付ける関数である。
modeにはモード(開くファイルの種類やデータの読み書きの方法)を指定する。
fopen関数は、ファイルのオープンに成功した場合は、オープンしたストリームを制御するオブジェクトへのポインタを返し、失敗した場合は、NULLを返す。
#include <stdio.h>
FILE * fopen(const char * restrict filename, const char * restrict mode);
第2引数のmodeに指定できるモードは以下の通りである。
モード | ファイル | 機能 | ファイルが存在しない場合の動作 |
---|---|---|---|
r | テキスト | 読み込み | エラー |
w | テキスト | 書き込み | 新規作成 |
a | テキスト | 追加書き込み | 新規作成 |
rb | バイナリ | 読み込み | エラー |
wb | バイナリ | 書き込み | 新規作成 |
ab | バイナリ | 追加書き込み | 新規作成 |
r+ | テキスト | 更新(読み込みおよび書き込み) | エラー |
w+ | テキスト | 更新(読み込みおよび書き込み) | 新規作成 |
a+ | テキスト | 更新(追加書き込み) | 新規作成 |
rb+ または r+b | バイナリ | 更新(読み込みおよび書き込み) | エラー |
wb+ または w+b | バイナリ | 更新(読み込みおよび書き込み) | 新規作成 |
ab+ または a+b | バイナリ | 更新(追加書き込み) | 新規作成 |
fopen関数を使用したファイルのオープンは、多くの場合、以下のような記述で実装される。
以下の例では、sample.txtファイルを書き込みモードでオープンしている。
char *filename = "sample.txt";
FILE *fp;
/* ファイルのオープン */
if ((fp = fopen(filename, "w")) == NULL)
{
/* エラー処理 */
}
/* 何らかの処理 */
/* ファイルのクローズ */
fclose(fp);
以下の例では、fopen関数を使用して、ファイルを書き込みモードでオープンしている。
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *fp;
char *filename = "sample.txt";
/* ファイルのオープン */
if ((fp = fopen(filename, "w")) == NULL)
{
fprintf(stderr, "%sのオープンに失敗しました.\n", filename);
exit(EXIT_FAILURE);
}
printf("ファイルのオープンに成功しました.\n");
printf("/*\n");
printf(" 普通はファイルに対して書き込みを行うコードを\n");
printf(" ここに書きます.\n");
printf("*/\n");
/* ファイルのクローズ */
fclose(fp);
return EXIT_SUCCESS;
}
ファイルを閉じる
読み書き等の処理が終わったファイルはクローズする。
C言語で、ファイルをクローズするには、stdio.hのfclose関数を使用する。
fclose関数は、streamが指すストリームに結び付けられたファイルをクローズする関数である。
fclose関数は、操作が成功した場合は0、失敗した場合はEOFを返す。
#include <stdio.h>
int fclose(FILE *stream);
以下の例では、fclose関数を使用してファイルをクローズしている。
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *fp;
char *filename = "sample.txt";
/* ファイルのオープン */
if ((fp = fclose(filename, "w")) == NULL)
{
fprintf(stderr, "%sのオープンに失敗しました.\n", filename);
exit(EXIT_FAILURE);
}
/* ファイルのクローズ */
fclose(fp);
printf("ファイルをクローズしました.\n");
return EXIT_SUCCESS;
}
ファイルをクローズしてから新しいファイルをオープンする
C言語で、ファイルをクローズしてから新しいファイルをオープンするには、freopen関数を使用する。
fopen関数とfclose関数を組み合わせて使用してもよいが、freopen関数は、1度の呼び出しでこれらの処理を行うため、短く記述できる。
freopen関数は、streamが指す既存のストリームをクローズしてから、filenameが指すファイルをmodeが指すモードでオープンして、
そのファイルにストリームを結び付ける関数である。
(指定可能なモードについては、fopen関数と同様である。詳しくは、上記のfopen関数のモードを参照すること)
freopen関数は、操作が成功した場合は、オープンしたストリームを制御するオブジェクトへのポインタを返し、失敗した場合はNULLを返す。
#include <stdio.h>
FILE * freopen(const char * restrict filename, const char * restrict mode, FILE * restrict stream);
以下の例では、freopen関数を使用して、ファイルをクローズしてから新しいファイルをオープンしている。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 256
int main(void)
{
FILE *fp;
char *filename = "sample.txt";
char *writeline = "I don't want to march as much as possible.";
char readline[N] = {'\0'};
/* ファイルを書き込みモードでオープン */
if ((fp = fopen(filename, "w")) == NULL)
{
fprintf(stderr, "%sのオープンに失敗しました.\n", filename);
exit(EXIT_FAILURE);
}
/* 文字列をsample.txtに書き込む */
fputs(writeline, fp);
/* ファイルをクローズし, 読み込みモードで再オープン */
if ((fp = freopen(filename, "r", fp)) == NULL)
{
fprintf(stderr, "%sの再オープンに失敗しました.\n 詳細:%s", filename, strerror(errno));
exit(EXIT_FAILURE);
}
/* ファイルの終端まで文字を読み取り表示する */
fgets(readline, N, fp);
puts(readline);
/* ファイルのクローズ */
fclose(fp);
return EXIT_SUCCESS;
}
ファイルから1文字ずつ文字を読み込む
C言語で、ファイルから1文字ずつ文字を読み込むには、stdio.hのfgetc
関数またはgetc
関数(マクロ)を使用する。
fgetc
関数は、streamが指すストリームから1文字分文字を読み取る関数である。
getc
関数は、基本的にはfgetc
関数と同様だが、処理系によっては関数ではなくマクロとして実装されている場合がある。
fgetc
関数とgetc
関数は、ストリームから正常に文字を読み取った場合は、読み取った文字を返す。
読み取りに失敗した場合やファイルの終端を読み取った場合は、EOF
(-1)を返す。
戻り値がint型である理由は、fgetc
関数で得た値をそのままfputc
関数で使用できるようにするためである。
#include <stdio.h>
int fgetc(FILE *stream);
int getc(FILE *stream);
以下の例では、fgetc関数を使用して、ファイルの終端まで文字を読み取っている。
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *fp;
char *filename = "sample.txt";
int ch;
/* ファイルのオープン */
if ((fp = fopen(filename, "r")) == NULL)
{
fprintf(stderr, "%sのオープンに失敗しました.\n", filename);
exit(EXIT_FAILURE);
}
/* ファイルの終端まで文字を読み取り表示する */
while (( ch = fgetc(fp)) != EOF )
{
putchar(ch);
}
/* ファイルのクローズ */
fclose(fp);
return EXIT_SUCCESS;
}
ファイルから1行ずつ文字列を読み込む
C言語で、ファイルから1行ずつ文字列を読み込むには、stdio.hのfgets関数を使用する。
fgets関数は、streamが指すストリームから改行文字またはファイルの終わりまで文字列を読み取り、sが指す配列に格納する関数である。
なお、n - 1が1行の最大入力文字数となる。
fgets関数は、ストリームから正常に文字列を読み取った場合は、読み取った文字列を返す。
読み取りに失敗した場合やファイルの終端を読み取った場合は、NULLを返す。
#include <stdio.h>
char *fgets (char * restrict s, int n, FILE * restrict stream);
以下の例では、fgets関数を使用して、ファイルの終端まで文字列を読み取っている。
#include <stdio.h>
#include <stdlib.h>
#define N 256
int main(void)
{
FILE *fp;
char *filename = "sample.txt";
char readline[N] = {'\0'};
/* ファイルのオープン */
if ((fp = fopen(filename, "r")) == NULL)
{
fprintf(stderr, "%sのオープンに失敗しました.\n", filename);
exit(EXIT_FAILURE);
}
/* ファイルの終端まで文字を読み取り表示する */
while ( fgets(readline, N, fp) != NULL )
{
printf("%s", readline);
}
/* ファイルのクローズ */
fclose(fp);
return EXIT_SUCCESS;
}
ファイルに1文字ずつ文字を書き込む
C言語で、ファイルに1文字ずつ文字を書き込むには、stdio.hのfputc関数またはputc関数(マクロ)を使用する。
fputc関数は、streamが指すストリームに、cで指定した文字を書き込む関数である。
putc関数は、基本的にはfputc関数と同じであるが、処理系によっては、関数ではなくマクロとして実装されている場合がある。
fputc関数とputc関数は、ストリームに正常に文字を書き込むことができた場合は書き込んだ文字を返し、書き込みに失敗した場合はEOFを返す。
#include <stdio.h>
int fputc(int c, FILE *stream);
int putc(int c, FILE *stream);
以下の例では、fputc関数を使用して、キーボードから入力された文字をファイルに書き込んでいる。
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *fp;
char *filename = "sample.txt";
int c;
/* ファイルのオープン */
if ((fp = fopen(filename, "w")) == NULL)
{
fprintf(stderr, "%sのオープンに失敗しました.\n", filename);
exit(EXIT_FAILURE);
}
/* 入力された文字をsample.txtに出力 */
while ((c = fgetc(stdin)) != EOF)
{
fputc(c, fp);
}
/* ファイルのクローズ */
fclose(fp);
return EXIT_SUCCESS;
}
ファイルに1行ずつ文字列を書き込む
C言語で、ファイルに1行ずつ文字列を書き込むには、stdio.hのfputs
関数を使用する。
fputs
関数は、streamが指すストリームにsが指す文字列を書き込む関数である。
fputs
関数は、ストリームに正常に文字列を書き込むことができた場合は0以上の値を返し、
全てのバイト列を書き終わる場合または書き込みに失敗した場合は、EOF
を返す。
問題が起きた場合は、原因を表す値が定数errno
に自動的に代入されるが、全てのバイト列が書き終わる場合と区別するため、定数errno
を0にする必要がある。
#include <stdio.h>
int fputs(const char * restrict s, FILE * restrict stream);
以下の例では、fputs
関数を使用して、文字列をファイルに書き込んでいる。
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
int main(void)
{
FILE *fp;
const char *filename = "sample.txt";
const char *writeline = "I don't want to march as much as possible.";
/* ファイルのオープン */
if ((fp = fopen(filename, "w")) == NULL)
{
fprintf(stderr, "%sのオープンに失敗しました.\n", filename);
exit(EXIT_FAILURE);
}
/* 文字列をsample.txtに書き込む */
errno = 0;
if(fputs(writeline, fp) == EOF)
{
if(errno != 0)
{
/* エラー処理 */
}
}
/* ファイルのクローズ */
fclose(fp);
return EXIT_SUCCESS;
}
また、puts
関数も存在する。
#include <stdio.h>
int puts(const char *buf);
puts
関数は、引数bufを標準出力に出力後、\nを出力する。
fputs
関数との違いは、出力先が標準出力に固定されていることと、\nを出力することである。
ただし、fgets
関数で入力した文字列には\nが付加されている場合があるため、
fgets
関数で読み込んだ文字列をそのままputs
関数に渡すと、\nが1つ余分に付加されることに注意すること。
書式文字列にしたがってファイルを読み込む
指定の書式にしたがって、ストリームからデータを取得するには、stdio.hのfscanf関数を使用する。
// C99以前
int fscanf ( FILE * stream, const char * format, ... );
// C99以降
int fscanf ( FILE * restrict stream, const char * restrict format, ... );
引数 stream : 取得するストリーム(FILE)へのポインタ。 format : 変換書式文字列。 詳細はscanf関数を参照すること。 ... : 入力を格納する変数群。(可変引数) 戻り値 代入された入力のバイト数を返す。 入力がない場合、または、入力誤りが発生した場合はEOFを返す。
#include <stdio.h>
int main()
{
FILE *fp;
char s[256] = {'\0'};
fp = fopen("Sample.txt", "r");
if(fp != NULL)
{
while(fscanf(fp, "%255[^\n]%*[^\n]", s) != EOF)
{
printf("Text=[%s]\n", s);
}
fclose(fp);
}
return 0;
}
下表に、入力フォーマットで指定可能な基本的な変換指定子を示す。
変換指定子 | データ型 | 詳細 |
---|---|---|
%hhd | char unsigned char |
10進数で解釈し、1バイトを変数へ格納する。 |
%hd | short unsigned short |
10進数で解釈し、2バイト整数を変数へ格納する。 |
%d | int unsigned int |
10進数で解釈し、int型変数へ格納する。 |
%ld | long unsigned long |
10進数で解釈し、4バイト変数へ格納する。 |
%hhx | char unsigned char |
16進数で解釈し、1バイト変数へ格納する。 |
%hx | short unsigned short |
16進数で解釈し、2バイト変数へ格納する。 |
%x | int unsigned int |
16進数で解釈し、int型変数へ格納する。 |
%lx | long unsigned long |
16進数で解釈し、4バイト変数へ格納する。 |
%f | float | 単精度浮動小数点数で解釈し、float型変数へ格納する。 |
%lf | double | 倍精度浮動小数点数で解釈し、double型変数へ格納する。 |
%c | char | 1文字として解釈し、char型変数へ文字として格納する。 |
%s | char * | 文字列として解釈し、文字列を格納する。 |
%p | void * | 16進数の番地として解釈し、番地を格納する。 |
書式文字列に従ってファイルに文字列を書き込む
printf関数のように、書式文字列に従ってファイルに文字列を書き込むには、stdio.hのfprintf関数を使用する。
fprintf関数は、formatが指す書式文字列に従って、streamが指すストリームへ書き込みを行う関数である。
なお、formatに指定できる書式文字列は、printf関数と同じである。
fprintf関数は、ストリームに正常に文字列を書き込むことができた場合は書き込んだ文字数を返し、書き込みに失敗した場合は負の値を返す。
#include <stdio.h>
int fprintf(FILE * restrict stream, const char * restrict format, ...);
以下の例では、fprintf関数を使用して、文字列をファイルに書き込んでいる。
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *fp;
char filename[] = "sample.txt";
int count = 0;
/* ファイルオープン */
if ((fp = fopen(filename, "w")) == NULL)
{
fprintf(stderr, "ファイルのオープンに失敗しました.\n");
return EXIT_FAILURE;
}
/* 書き込み */
count = fprintf(fp, "マンガ %s は %d 年に誕生しました.\n", "ピーナッツ", 1950);
if ( count < 0 )
{
fprintf(stderr, "ファイルの書込みに失敗しました.\n");
fclose(fp);
return EXIT_FAILURE;
}
fprintf(stdout, "%s へ %d 文字 (byte) 出力しました.\n", filename, count);
/* ファイルクローズ */
fclose(fp);
return EXIT_SUCCESS;
}
バイナリファイルからデータを読み込む
C言語で、バイナリファイルからデータを読み込むには、stdio.hのfread関数を使用する。
fread関数は、streamが指すストリームから、sizeバイト単位でnmemb個のデータを読み込み、ptrが指す配列に格納する関数である。
fread関数は、ストリームから正常にデータを読み取った場合は、読み取った要素の個数を返す。
読み取りに失敗した場合やファイルの終端を読み取った場合は、nmembより小さい値を返す。
※バイナリファイルを扱う場合は、fopen関数でファイルをオープンする際に、バイナリモードでオープンする必要がある。
#include <stdio.h>
size_t fread (void * restrict ptr, size_t size, size_t nmemb, FILE * restrict stream);
以下の例では、fread関数を使用して、バイナリファイルからデータを読み込んでいる。
#include <stdio.h>
#include <stdlib.h>
#define N 256
int main(void)
{
FILE *fp;
char *filename = "sample.txt";
int ptr[N];
size_t size;
/* ファイルのオープン */
if ((fp = fopen(filename, "rb")) == NULL)
{
fprintf(stderr, "%sのオープンに失敗しました.\n", filename);
exit(EXIT_FAILURE);
}
/* 読み込む */
size = fread(ptr, sizeof(int), 6, fp);
for (int i = 0; i < size; i++)
{
printf("%d\n", ptr[i]);
}
/* ファイルのクローズ */
fclose(fp);
return EXIT_SUCCESS;
}
バイナリファイルにデータを書き込む
C言語で、バイナリファイルにデータを書き込むには、stdio.hのfwrite関数を使用する。
fwrite関数は、ptrが指す配列から、sizeバイト単位でnmemb個のデータをstreamが指すストリームに書き込む関数である。
fwrite関数は、ストリームに正常にデータを書き込むことができた場合は書き込んだ要素の個数を返し、
書き込みに失敗した場合はnmembより小さい値を返す。
※バイナリファイルを扱う場合は、fopen関数でファイルをオープンする際に、バイナリモードでオープンする必要がある。
#include <stdio.h>
size_t fwrite (const void * restrict ptr, size_t size, size_t nmemb, FILE * restrict stream);
以下の例では、fwrite関数を使用して、バイナリファイルにデータを書き込んでいる。
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *fp;
char *filename = "sample.txt";
int ptr[] = {1, 255, 0x01, 0xff};
/* ファイルのオープン */
if ((fp = fopen(filename, "wb")) == NULL)
{
fprintf(stderr, "%sのオープンに失敗しました.\n", filename);
exit(EXIT_FAILURE);
}
/* ファイルにデータを書き込む */
fwrite(ptr, sizeof(int), 4, fp);
/* ファイルのクローズ */
fclose(fp);
return EXIT_SUCCESS;
}
一時的なバイナリファイルを作成する
C言語で、一時的なバイナリファイルを作成するには、stdio.hのtmpfile関数を使用する。
tmpfile関数は、既存のファイルとは異なる一時的なバイナリファイルを作成する関数である。
tmpfile関数で作成したバイナリファイルは、作成時に更新モード ("wb+") でオープンされる。
また、生成したファイルは、ファイルのクローズ時またはプログラムの終了時に自動的に削除される。
tmpfile関数は、操作が成功した場合は作成したファイルへのポインタを返し、操作が失敗した場合はNULLを返す。
#include <stdio.h>
FILE *tmpfile(void);
以下の例では、tmpfile関数を使用して、一時的なバイナリファイルを作成してデータを書き込んだ後、そのファイルからデータを読み込んで表示している。
#include <stdio.h>
#include <stdlib.h>
#define N 256
int main(void)
{
char readline[N] = {'\0'};
FILE *fp;
/* 一時ファイルの作成 */
if ( (fp = tmpfile()) == NULL )
{
fprintf(stderr, "一時ファイルの作成に失敗しました.\n");
return EXIT_FAILURE;
}
/* 一時ファイルに適当に文字列を書き込む */
for (int i = 0; i < 5; i++ )
{
fprintf(fp, "test%d\n", i);
}
/* 念のためバッファフラッシュする */
fflush(fp);
/* ファイル位置表示子を戻す */
rewind(fp);
/* 一時ファイルから文字列を読み込む */
while ( fgets(readline, N, fp) != NULL )
{
fprintf(stdout, "%s", readline);
}
/* 一時ファイルのクローズ(削除) */
fclose(fp);
return EXIT_SUCCESS;
}
ファイル位置表示子をそのファイルの始めに位置付ける
C言語で、ファイル位置表示子をそのファイルの始めに位置付けるには、stdio.hのrewind関数を使用する。
rewind関数は、streamが指すストリームのファイル位置表示子を、そのファイルの始めに位置付ける関数である。
#include <stdio.h>
void rewind (FILE *stream);
以下の例では、rewind関数を使用して、ファイル位置表示子をファイルの始めに位置付けている。
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *fp;
char *filename = "sample.txt";
int ch;
/* ファイルのオープン */
if ((fp = fopen(filename, "r")) == NULL)
{
fprintf(stderr, "%sのオープンに失敗しました.\n", filename);
exit(EXIT_FAILURE);
}
/* 7文字読み取り */
for (int i = 0; i < 7; i++)
{
if ((ch = fgetc(fp)) != EOF)
{
putchar(ch);
}
}
putchar('\n');
/* ファイル位置表示子を先頭に戻す */
rewind(fp);
/* 7文字読み取り */
for (int i = 0; i < 7; i++)
{
if ((ch = fgetc(fp)) != EOF)
{
putchar(ch);
}
}
putchar('\n');
/* ファイルのクローズ */
fclose(fp);
return EXIT_SUCCESS;
}
実行例
上記で使用するsample.txtの内容は、以下のように用意したとする。
I don't want to march as much as possible.
上記の例での実行結果は以下のようになる。
I don't I don't
ファイル位置表示子を指定した位置に位置付ける
C言語で、ファイル位置表示子を指定した位置に位置付けるには、stdio.hのfseek関数を使用する。
fseek関数は、ファイル位置表示子の値を変更する関数である。
fseek関数は、streamが指すストリームが、バイナリストリームの場合とテキストストリームの場合で使い方が異なる。
#include <stdio.h>
int fseek (FILE *stream, long offset, int whence);
この関数は理解することが難しいので、まず、引数の説明から記載する。
fseek関数の引数
fseek関数の引数は以下の通りである。
- stream : ストリーム
- offset : 基準位置から移動するバイト数
- whence : 基準位置
基準位置whenceには、以下の3種類のマクロが指定できる。
- SEEK_SET: ファイルの先頭
- SEEK_CUR: ファイルの現在位置
- SEEK_END: ファイルの終端
fseek 関数の動作 - バイナリストリームの場合
バイナリストリームの場合、基準位置whenceが示す位置にoffsetを加えた値が新しい位置になる。
ただし、whenceにSEEK_ENDを指定した場合の動作は、処理系によってはサポートされていない場合があるので注意する。
fseek 関数の動作 - テキストストリームの場合
バイナリストリームとは異なり、テキストストリームの場合は、offsetに0または事前にftell関数で取得しておいた値のみ指定できる。
また、offsetにftell関数の値を指定した場合は、whenceにSEEK_SETを指定しなければならない。
テキストストリームに対してのfseek関数の動作をまとめると以下の4種類になる。
- offset = 0,whence = SEEK_SET: ファイルの先頭に位置付ける
- offset = 0,whence = SEEK_CUR: ファイルの現在位置に位置付ける
- offset = 0,whence = SEEK_END: ファイルの終端に位置付ける
- offset = ftell 関数の値,whence = SEEK_SET: ftell 関数で取得しておいた値の位置に位置付ける
以下の例では、fseek関数を使用して、ファイル位置表示子を指定した位置に位置付けている。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 256
int main(void)
{
FILE *fp;
char *filename = "sample.txt";
char ptr[N] = {'\0'};
size_t size;
/* ファイルのオープン */
if ((fp = fopen(filename, "rb")) == NULL)
{
fprintf(stderr, "%sのオープンに失敗しました.\n", filename);
exit(EXIT_FAILURE);
}
/* 7文字分読み込む */
size = fread(ptr, sizeof(char), 7, fp);
/* 表示 */
for (int i = 0; i < size; i++)
{
printf("%c", ptr[i]);
}
/* 現在位置から5バイト進める */
fseek(fp, 5, SEEK_CUR);
/* 配列の初期化 */
memset(ptr, '\0', N);
/* 10文字分読み込む */
size = fread(ptr, sizeof(char), 10, fp);
/* 表示 */
for (int i = 0; i < size; i++)
{
printf("%c", ptr[i]);
}
printf("\n");
/* ファイルのクローズ */
fclose(fp);
return EXIT_SUCCESS;
}
実行例
上記で使用するsample.txtの内容は、以下のように用意したとする。
I don't want to march as much as possible.
この時、実行結果は以下のようになる。
I don't to march
ファイル位置表示子がファイルの終端に達しているかどうかを判定する
C言語で、ファイル位置表示子がファイルの終端に達しているかどうかを判定するには、stdio.hのfeof関数を使用する。
feof関数は、streamが指すストリームのファイル終了表示子を判定する関数である。
feof関数は、ファイル終了表示子がセットされている場合は0以外、セットされていない場合は0を返す。
#include <stdio.h>
int feof (FILE *stream);
以下の例では、feof関数を使用して、ファイル位置表示子がファイルの終端に達しているかどうかを判定している。
#include <stdio.h>
#include <stdlib.h>
#define N 256
int main(void)
{
FILE *fp;
char *filename = "sample.txt";
char readline[N] = {'\0'};
/* ファイルのオープン */
if ((fp = fopen(filename, "r")) == NULL)
{
fprintf(stderr, "%sのオープンに失敗しました.\n", filename);
exit(EXIT_FAILURE);
}
/* ファイル終了表示子のチェック */
printf("読込み前: feof(fp) = %d\n", feof(fp));
/* ファイルの終端まで文字を読み取る */
while ( fgets(readline, N, fp) != NULL );
/* ファイル終了表示子のチェック */
printf("読込み後: feof(fp) = %d\n", feof(fp));
/* ファイルのクローズ */
fclose(fp);
return EXIT_SUCCESS;
}
ファイルでエラーが発生しているかどうかを判定する
C言語で、ファイルでエラーが発生しているかどうかを判定するには、stdio.hのferror関数を使用する。
ferror関数は、streamが指すストリームのエラー表示子を判定する関数である。
ferror関数は、エラー表示子がセットされている場合は0以外、セットされていない場合は0を返す。
#include <stdio.h>
int ferror (FILE *stream);
以下の例では、ferror関数を使用して、ファイルでエラーが発生しているかどうかを判定している。
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *fp;
char *filename = "sample.txt";
int ch;
/* ファイルのオープン */
if ((fp = fopen(filename, "w")) == NULL)
{
fprintf(stderr, "%sのオープンに失敗しました.\n", filename);
exit(EXIT_FAILURE);
}
/* エラー表示子のチェック */
printf("書込み前: ferror(fp) = %d\n", ferror(fp));
ch = fgetc(fp);
fputc(ch, fp);
/* エラー表示子のチェック */
printf("書込み後: ferror(fp) = %d\n", ferror(fp));
/* ファイルのクローズ */
fclose(fp);
return EXIT_SUCCESS;
}