【初心者向け】C言語 fsetpos 関数:ファイル入出力の位置制御をわかりやすく解説
- 正常終了した場合には 0 を、エラー発生時には -1 を返します。
- 移動先の位置は、
fpos_t
型の構造体pos
で指定されます。この構造体は、fgetpos
関数によって取得することができます。 - 対象となるファイルは、
FILE
型のポインタで渡されます。 - ファイルポインタを指定した位置に移動します。
利点
- 繰り返し同じ箇所へアクセスする場合などに有効です。
- ファイル全体を順番に読み込む必要がなくなり、処理効率が向上します。
- ランダムアクセスと呼ばれる、ファイル内の任意の位置へ直接アクセスすることが可能です。
具体的な使用方法
#include <stdio.h>
int main() {
FILE *fp;
fpos_t pos;
// ファイルを開く
fp = fopen("data.txt", "r");
if (fp == NULL) {
perror("fopen");
return 1;
}
// ファイル位置を取得
if (fgetpos(fp, &pos) != 0) {
perror("fgetpos");
fclose(fp);
return 1;
}
// ファイル位置を移動
if (fsetpos(fp, &pos) != 0) {
perror("fsetpos");
fclose(fp);
return 1;
}
// 現在の位置からデータを読み込む
char buf[1024];
int n = fread(buf, 1, sizeof(buf), fp);
if (n < 0) {
perror("fread");
fclose(fp);
return 1;
}
// 読み込んだデータを出力
printf("%s", buf);
// ファイルを閉じる
fclose(fp);
return 0;
}
注意点
- マルチバイト文字を含むファイルに対して
fsetpos
関数を使用する場合は、文字化けが発生する可能性があります。その場合は、setlocale
関数を使用してロケールを設定する必要があります。 - ファイルの書き込みを行う場合は、
fsetpos
関数を使用する前に、fseek
関数を使用してファイルの書き込み位置を設定する必要があります。 fsetpos
関数は、fgetpos
関数で取得した値のみを許容します。他の方法で取得した値を使用すると、予期せぬ動作を引き起こす可能性があります。
上記以外にも、fsetpos
関数に関する情報は以下のリソースで確認することができます。
#include <stdio.h>
int main() {
FILE *fp_read, *fp_write;
fpos_t pos;
char buf[1024];
// 読み込み対象のファイルを開く
fp_read = fopen("input.txt", "r");
if (fp_read == NULL) {
perror("fopen");
return 1;
}
// 書き込み対象のファイルを開く
fp_write = fopen("output.txt", "w");
if (fp_write == NULL) {
perror("fopen");
fclose(fp_read);
return 1;
}
// ファイル位置を 100 バイト目に設定
pos.st = 100;
pos.lOffset = 0;
if (fsetpos(fp_read, &pos) != 0) {
perror("fsetpos");
fclose(fp_read);
fclose(fp_write);
return 1;
}
// 1024 バイト分のデータを読み込む
int n = fread(buf, 1, sizeof(buf), fp_read);
if (n < 0) {
perror("fread");
fclose(fp_read);
fclose(fp_write);
return 1;
}
// 読み込んだデータを書き込む
fwrite(buf, 1, n, fp_write);
if (n < 0) {
perror("fwrite");
fclose(fp_read);
fclose(fp_write);
return 1;
}
// ファイルを閉じる
fclose(fp_read);
fclose(fp_write);
return 0;
}
fopen
関数を使用して、読み込み対象のファイルと書き込み対象のファイルを開きます。fsetpos
関数を使用して、読み込み対象ファイルの位置を 100 バイト目に設定します。fread
関数を使用して、1024 バイト分のデータを読み込みます。fwrite
関数を使用して、読み込んだデータを書き込みます。fclose
関数を使用して、開いたファイルを閉じます。
- エラー処理をより詳細に行うこともできます。
- ファイルパスや読み込む/書き込むデータ量などは、自由に設定できます。
- このコードはあくまで一例であり、状況に応じて変更する必要があります。
fseek 関数
fseek
関数は、fsetpos
関数と同様にファイルポインタを移動するために使用できます。主な違いは以下の通りです。
- 欠点
fsetpos
関数よりも古い関数であり、一部の古いコンパイラではサポートされていない場合があります。fpos_t
型の構造体を使用する必要があり、fsetpos
関数よりも扱いづらい場合があります。
- 利点
fsetpos
関数よりも汎用性が高く、ファイルの開始位置からのオフセット量だけでなく、現在の位置からの相対位置も指定できます。- シークモードを指定することで、ファイルの読み書き位置をより柔軟に制御できます。
例
#include <stdio.h>
int main() {
FILE *fp;
// ファイルを開く
fp = fopen("data.txt", "r");
if (fp == NULL) {
perror("fopen");
return 1;
}
// ファイル位置を 100 バイト目に移動
fseek(fp, 100, SEEK_SET);
// 現在の位置からデータを読み込む
char buf[1024];
int n = fread(buf, 1, sizeof(buf), fp);
if (n < 0) {
perror("fread");
fclose(fp);
return 1;
}
// 読み込んだデータを出力
printf("%s", buf);
// ファイルを閉じる
fclose(fp);
return 0;
}
ftell 関数と fseek 関数の組み合わせ
ftell
関数は、現在のファイルポインタの位置を取得するために使用できます。この値を fseek
関数のオフセット量として使用することで、fsetpos
関数と同等の機能を実現することができます。
利点
fsetpos
関数よりも簡潔なコードで記述できます。
欠点
- 2 つの関数呼び出しが必要となるため、
fsetpos
関数よりも若干処理効率が低下します。
例
#include <stdio.h>
int main() {
FILE *fp;
long pos;
// ファイルを開く
fp = fopen("data.txt", "r");
if (fp == NULL) {
perror("fopen");
return 1;
}
// 現在の位置を取得
pos = ftell(fp);
// ファイル位置を 100 バイト目に移動
fseek(fp, pos + 100, SEEK_SET);
// 現在の位置からデータを読み込む
char buf[1024];
int n = fread(buf, 1, sizeof(buf), fp);
if (n < 0) {
perror("fread");
fclose(fp);
return 1;
}
// 読み込んだデータを出力
printf("%s", buf);
// ファイルを閉じる
fclose(fp);
return 0;
}
システムコールの使用
低レベルなプログラミングが必要な場合は、lseek
などのシステムコールを使用してファイルポインタを移動することができます。
利点
- 細かい制御が可能
欠点
- ポータビリティが低い
- 複雑で、エラー処理が難しい
#include <unistd.h>
#include <stdio.h>
int main() {
int fd;
off_t pos;
// ファイルを開く
fd = open("data.txt", O_RDONLY);
if (fd < 0) {
perror("open");
return 1;
}
// 現在の位置を取得
pos = lseek(fd, 0, SEEK_CUR);
if (pos < 0) {
perror("lseek");
close(fd);
return 1;
}
// ファイル位置を 100 バイト目に移動
pos += 100;
if (l