学习笔记
lseek函数
文件偏移
以前有接触到fseek 库函数,lseek和它有点类似。
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
第一个参数:文件描述符
第二个参数:偏移量 正负值, 往前往后
第三个参数:设置偏移的起始位置 whence: 从何处,从哪里的意思
三个值:
SEEK_SET :文件的起始位置
SEEK_CUR :文件的当前位置
SEEK_END :文件的末尾位置
返回值:
off_t:一定是与起始位置开始向后的偏移量
错误的时候,返回值为-1,并且设置errno (#include <errno.h>)
注意:文件的读和写使用相同的偏移量。
查看程序:
注意strlen长度不包含'\0'。
$cat lseek.c
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<fcntl.h>
int main(void)
{
int fd,n;
char msg[] = "It's a test for lseek\n";
char ch;
fd = open("lseek.txt",O_RDWR|O_CREAT,0664);
if(-1 == fd )
{
perror("open lseek.txt error!");
exit(1);
}
write(fd,msg,strlen(msg));
//lseek(fd,0,SEEK_SET);
while(( n = read(fd,&ch,1)))
{
if( -1 == n)
{
perror("read error");
exit(1);
}
write(STDOUT_FILENO,&ch,n);
}
close(fd);
return 0;
}
read 返回值为0的时候,就是文件末尾了。
$./lseek
$ll
total 40
drwxrwxr-x 2 ubuntu ubuntu 4096 12月 22 23:10 ./
drwxrwxr-x 7 ubuntu ubuntu 4096 12月 22 22:58 ../
-rwxrwxr-x 1 ubuntu ubuntu 19800 12月 22 23:10 lseek*
-rw-rw-r-- 1 ubuntu ubuntu 495 12月 22 23:09 lseek.c
-rw-rw-r-- 1 ubuntu ubuntu 22 12月 22 23:10 lseek.txt
-rwxr--r-- 1 ubuntu ubuntu 178 12月 22 22:58 makefile*
$cat lseek.txt
It's a test for lseek
将下面的//去除
//lseek(fd,0,SEEK_SET);
执行的结果不一样,终端也会输出内容。
$vim lseek.c
$make
gcc lseek.c -o lseek -Wall -g
$./lseek
It's a test for lseek
结论:文件的读和写使用相同的偏移量!!!
应用的场景:
1.文件的读和写使用相同的偏移位置
2.使用lseek取获取文件大小
3.使用lseek取拓展文件大小,要想文件真正的拓展,必需引起IO操作。
通过lseek 去获取文件大小,是一个野路子
正规方式后面再介绍。
使用lseek获取文件的大小很常见。我们就从众吧。
方式:lseek(fd,0,SEEK_END);
查看下面代码:
$cat lseek_test.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>
#include<fcntl.h>
int main(int argc, char* argv[])
{
int fd;
int length;
fd = open(argv[1],O_RDWR);
if(-1 == fd)
{
perror("open error!");
exit(1);
}
length = lseek(fd,0,SEEK_END);
printf("file size: %d\n",length);
close(fd);
return 0;
}
$ll
total 64
drwxrwxr-x 2 ubuntu ubuntu 4096 12月 22 23:32 ./
drwxrwxr-x 7 ubuntu ubuntu 4096 12月 22 22:58 ../
-rwxrwxr-x 1 ubuntu ubuntu 19848 12月 22 23:20 lseek*
-rw-rw-r-- 1 ubuntu ubuntu 496 12月 22 23:20 lseek.c
-rwxrwxr-x 1 ubuntu ubuntu 19808 12月 22 23:32 lseek_test*
-rw-rw-r-- 1 ubuntu ubuntu 336 12月 22 23:32 lseek_test.c
-rw-rw-r-- 1 ubuntu ubuntu 22 12月 22 23:20 lseek.txt
-rwxr--r-- 1 ubuntu ubuntu 178 12月 22 22:58 makefile*
$./lseek_test ./lseek.c
file size: 496
都是496。
添加一个f.c
$./lseek_test ./f.c
file size: 440
如何扩展到500.拓展文件大小的程序:
$cat lseek_test.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>
#include<fcntl.h>
int main(int argc, char* argv[])
{
int fd;
int length;
fd = open(argv[1],O_RDWR);
if(-1 == fd)
{
perror("open error!");
exit(1);
}
length = lseek(fd,60,SEEK_END);
printf("file size: %d\n",length);
close(fd);
return 0;
}
$make clean
rm -rf ./lseek_test ./f ./lseek a.out
$make lseek_test
gcc lseek_test.c -o lseek_test -Wall -g
$ll
total 5520
drwxrwxr-x 2 ubuntu ubuntu 4096 12月 22 23:50 ./
drwxrwxr-x 7 ubuntu ubuntu 4096 12月 22 22:58 ../
-rwxr--r-- 1 ubuntu ubuntu 5600268 12月 18 17:52 dict.txt.txt*
-rwxr--r-- 1 ubuntu ubuntu 440 12月 22 23:41 f.c*
-rw-rw-r-- 1 ubuntu ubuntu 496 12月 22 23:20 lseek.c
-rwxrwxr-x 1 ubuntu ubuntu 19864 12月 22 23:50 lseek_test*
-rw-rw-r-- 1 ubuntu ubuntu 351 12月 22 23:48 lseek_test.c
-rw-rw-r-- 1 ubuntu ubuntu 22 12月 22 23:20 lseek.txt
-rwxr--r-- 1 ubuntu ubuntu 178 12月 22 22:58 makefile*
$./lseek_test f.c
file size: 500
$ls -l f.c
-rwxr--r-- 1 ubuntu ubuntu 440 12月 22 23:41 f.c
发现有趣的现象。
原因:没有进行IO操作。
修改程序:
$cat lseek_test.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>
#include<fcntl.h>
int main(int argc, char* argv[])
{
int fd;
int length;
fd = open(argv[1],O_RDWR);
if(-1 == fd)
{
perror("open error!");
exit(1);
}
length = lseek(fd,59,SEEK_END);
printf("file size: %d\n",length);
write(fd,"a",1);
close(fd);
return 0;
}
$make lseek_test
gcc lseek_test.c -o lseek_test -Wall -g
$./lseek_test ./f.c
file size: 499
$ll
total 5520
drwxrwxr-x 2 ubuntu ubuntu 4096 12月 22 23:57 ./
drwxrwxr-x 7 ubuntu ubuntu 4096 12月 22 22:58 ../
-rwxr--r-- 1 ubuntu ubuntu 5600268 12月 18 17:52 dict.txt.txt*
-rwxr--r-- 1 ubuntu ubuntu 500 12月 22 23:57 f.c*
-rw-rw-r-- 1 ubuntu ubuntu 496 12月 22 23:20 lseek.c
-rwxrwxr-x 1 ubuntu ubuntu 19904 12月 22 23:57 lseek_test*
-rw-rw-r-- 1 ubuntu ubuntu 369 12月 22 23:57 lseek_test.c
-rw-rw-r-- 1 ubuntu ubuntu 22 12月 22 23:20 lseek.txt
-rwxr--r-- 1 ubuntu ubuntu 178 12月 22 22:58 makefile*
filesize为499(因为最后写的a,没有算进去)
ll查看为500.
查看f.c文件
我们将2(没有扩展之前的最后一个字2)和字母a之间的内容一堆^@称为文件空洞,二进制形态为\0.
od -tcx filename 查看文件的16进制表示形式
od -tcd filename 查看文件的10机制表示形式
下面的内容还是有点迷糊。
$od -tcd f.c
0000000 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
825307441 825307441 825307441 825307441
*
0000660 1 1 1 1 1 1 1 2 \0 \0 \0 \0 \0 \0 \0 \0
825307441 842084657 0 0
0000700 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0
0 0 0 0
*
0000760 \0 \0 \0 a
1627389952
0000764
truncate函数也可以用来扩展函数的大小
#include <unistd.h>
#include <sys/types.h>
int truncate(const char *path, off_t length);
第一个参数:文件路径,文件必须存在
第二个参数:文件长度
返回:
成功是0
失败是1
int ftruncate(int fd, off_t length);
程序:
$cat trunc.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>
int main(int argc, char *argv[])
{
//open/lseek(fd,249,SEEK_END);/write(fd,"\0",1);//zheyangzi jiudedao 250
int ret = truncate("./dict.cp",250);
printf("ret= %d\n",ret);
return 0;
}
$make trunc
gcc trunc.c -o trunc -Wall -g
$./trunc
ret= -1
$touch dict.cp
$ls -l dict.cp
-rw-rw-r-- 1 ubuntu ubuntu 0 12月 23 00:19 dict.cp
$./trunc
ret= 0
$ll dict.cp
-rw-rw-r-- 1 ubuntu ubuntu 250 12月 23 00:19 dict.cp