第21章 lseek()

 lseek() 関数はファイルオフセットを調整してくれる関数です。

 ファイルオフセットとは読み込む開始位置です。

#include <sys/types.h>
#include <unistd.h>

off_t lseek(int fd, off_t offset, int whence);

 fd はファイル記述子で off_t はオフセット、 whence は以下の3種類のいずれかとなります。

SEEK_SET
offset バイトにファイルオフセットを設定
SEEK_CUR
現在の位置+ offset バイトにファイルオフセットを設定
SEEK_END
ファイルサイズ+ offset バイトにファイルセットを設定

 whence にはそれ以外の種類もあるようですが、この項目ではこの3つだけ使ってみたいと思います。

 それで実装例を見てみましょう。

main.c. 

  1 #include <sys/types.h>
  2 #include <unistd.h>
  3 #include <fcntl.h>
  4 #include <stdio.h>
  5 #include <stdlib.h>
  6
  7 int main()
  8 {
  9   char *buf;
 10   int fd, size, pos;
 11
 12   buf = (char *) calloc(100, sizeof(char));
 13   fd = open("abc.txt", O_RDONLY);
 14   if (fd < 0) {
 15     perror("r1");
 16     exit(1);
 17   }
 18
 19   size = read(fd, buf, 5);
 20   printf("read(%d, buf, 5)\n", fd);
 21   printf("%d バイト\n", size);
 22   buf[size] = '\0';
 23   printf("%s\n\n", buf);
 24
 25   pos = lseek(fd, 2, SEEK_CUR);
 26   printf("lseek(%d, 2, SEEK_CUR) => %d\n", fd,pos);
 27   size = read(fd, buf, 5);
 28   printf("read(%d, buf, 5) => %d\n",fd,size);
 29   printf("%s\n\n",buf);
 30
 31   pos = lseek(fd, 0, SEEK_SET);
 32   printf("lseek(%d,0,SEEK_SET) => %d\n",fd,pos);
 33   size = read(fd, buf, 5);
 34   printf("read(%d, buf, 5) => %d\n",fd,size);
 35   buf[size] = '\0';
 36   printf("%s\n\n", buf);
 37
 38   pos = lseek(fd,-10,SEEK_END);
 39   printf("lseek(%d, -10, SEEK_END) => %d\n",fd,pos);
 40   size = read(fd, buf, 5);
 41   printf("read(%d, buf, 5) => %d\n", fd,size);
 42   buf[size] = '\0';
 43   printf("%s\n", buf);
 44
 45   return 0;
 46 }

ビルドと実行結果. 

$ echo "abcde123456789" > abc.txt
$ gcc main.c
$ ./a.out
read(3, buf, 5)
5 バイト
abcde

lseek(3, 2, SEEK_CUR) => 7
read(3, buf, 5) => 5
34567

lseek(3,0,SEEK_SET) => 0
read(3, buf, 5) => 5
abcde

lseek(3, -10, SEEK_END) => 5
read(3, buf, 5) => 5
12345

 出力が長めですね…

 すんません… (´・ω・`)

 それで最初の出力部分です。

 19   size = read(fd, buf, 5);
 20   printf("read(%d, buf, 5)\n", fd);
 21   printf("%d バイト\n", size);
 22   buf[size] = '\0';
 23   printf("%s\n\n", buf);

 まあこれは「read(fd,buf,5)」によって 5 バイトだけ buf に読みこんでるだけですね。

 まだこの段階で lseek() 関数は使ってません。

 では次の出力を見たいと思いますが、空の行があいたコードのことです。

 25   pos = lseek(fd, 2, SEEK_CUR);
 26   printf("lseek(%d, 2, SEEK_CUR) => %d\n", fd,pos);
 27   size = read(fd, buf, 5);
 28   printf("read(%d, buf, 5) => %d\n",fd,size);
 29   printf("%s\n\n",buf);

 「 lseek(3, 2, SEEK_CUR) 」というのは SEEK_CUR が 5 になってるので、それにオフセット 2 を足すと 7 バイトになりますね。

 なので lseek() は 7 を返します。

 そして「 read(3, buf, 5) 」は 5 を返します。

 buf の中身は 7 バイトオフセットを移動してから read() で 5 バイトを読み込んでるので「34567」を出力します。

 では次の出力に該当するコードです。

 31   pos = lseek(fd, 0, SEEK_SET);
 32   printf("lseek(%d,0,SEEK_SET) => %d\n",fd,pos);
 33   size = read(fd, buf, 5);
 34   printf("read(%d, buf, 5) => %d\n",fd,size);
 35   buf[size] = '\0';
 36   printf("%s\n\n", buf);

 「 lseek(3,0,SEEK_SET) 」はファイルオフセットを 0 の位置に戻します。

 なぜなら SEEK_SET は offset 引数に指定した値をファイルオフセットに指定するからです。

 この場合は offset 引数は 0 なのでファイルオフセットは 0 になります。

 では最後の出力箇所に該当するコードです。

 38   pos = lseek(fd,-10,SEEK_END);
 39   printf("lseek(%d, -10, SEEK_END) => %d\n",fd,pos);
 40   size = read(fd, buf, 5);
 41   printf("read(%d, buf, 5) => %d\n", fd,size);
 42   buf[size] = '\0';
 43   printf("%s\n", buf);

 「 lseek(3, -10, SEEK_END) 」はファイルサイズ、すなわちファイルの終わりのファイルオフセットから -10 の位置を返します。

 つまり lseek() は 5 を返します。

 それと「read(3, buf, 5)」は 5 バイトだけ buf を読み込みます

 位置が 5 で 5 バイト読み込みます。

 buf を printf() で出力すると「 12345 」になります。

Copyright 2018-2019, by Masaki Komatsu