【初心者向け】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;
}
  1. fopen 関数を使用して、読み込み対象のファイルと書き込み対象のファイルを開きます。
  2. fsetpos 関数を使用して、読み込み対象ファイルの位置を 100 バイト目に設定します。
  3. fread 関数を使用して、1024 バイト分のデータを読み込みます。
  4. fwrite 関数を使用して、読み込んだデータを書き込みます。
  5. 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