关于流的概念
文件读写的时候是一个一个字符读写的,然后这些按着顺序读写的字符就构成了字符流,这些字符被动态连续的处理,形成了流。
文件指针
在windows操作文件的时候,会有一个光标来显示当前要操作的位置,这个位置就是文件指针。
在linux中,文件指针不能被直接操作,可以利用read、write这两个函数进行间接操作,也可以用lseek这个函数来进行人为更改文件指针的位置。
off_t lseek(int fd, off_t offset, int whence);
这个是lseek的原型,使用这个API的话需要传三个参数:
第一个是fd文件描述符;
第二个是偏移量,用来给你设置你要偏移的字符位数;
第三个是whence参数
可以选择SEEK_SET、SEEK_CUR、SEEK_END这三个
SEEK_SET
The file offset is set to offset bytes.
这个表示把文件指针放在你设置的偏移量的位置,这个偏移量是相对于文件开头而言,
比如说你设置了2,则文件指针就在第二个字符的后面,
像Windows下的光标,在第二个字符后面“一闪一闪”。
SEEK_CUR
The file offset is set to its current location plus offset bytes.
这个表示文件指针的位置设置在当前位置加上你设置的offset值的位置。比如说你的
当前文件指针在第三个字符后面,你设置了offset值是2,那么最终的文件指针就在3+2=5
在第五个字符后面。
SEEK_END
The file offset is set to the size of the file plus offset bytes.
这个表示文件指针的位置是文件末尾的位置加上设置的offset值的和的位置。
在terminal上面打印出来的话看不了到底是不是有移动,
但是用vim打开的话可以很明显看到有两个@@多了出来,因为我设置的offset值是2.
plus.我在测试的时候发现,如果在Windows下先编辑文件,
然后再通过设置SEEK_END这些的话,文件加上去的地方还是在末尾的,
如果在linux下用vim打开过的话呢就会出现自动换行的现象。
测试的时候发现如果编辑文件在vim打开过之后,后面执行了都会自动换行。
用lseek来计算文件长度
- 用lseek计算文件长度的原理就是利用lseek函数的返回值特性,它的返回值是返回当前文件指针相对于文件第一个字符的偏移量,所以用到SEEK_END的特性,把文件指针移动到末尾,同时偏移量设置为0,即文件指针被移动的位置是末尾位置+0也就是末尾的位置了。
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc,char *argv[])
{
//打开文件
if(argc != 2)
{
printf("用法:%s 文件名\n",argv[0]);
return -1;
}
int fd = -1;
fd = open(argv[1],O_RDWR);
if (-1 == fd)
{
printf(" file open fail\n");
}
else
{
printf("file open success , fd = %d \n",fd);
}
//计算长度
int ret = -1;
ret = lseek(fd ,0,SEEK_END);
printf("文件长度为%d字节\n", ret);
#if 0
//写文件
int w_ret = -1;
char buf2 [] = "a22";
w_ret = write(fd,buf2,sizeof(buf2));
if (-1 == w_ret)
{
printf("write fail\n");
}
else
{
printf("write success,写入了%d个字节\n",w_ret);
printf("w_ret = %d\n",w_ret);
}
#endif
#if 0
//读取文件
char buf[100] = {0};
int ret = -1;
ret = read(fd,buf, 20);
if (-1 == ret)
{
printf("read file fail");
}
else
{
printf("实际读取了%d字节\n",ret);
printf("文件内容是\n[\n%s]\n",buf);
printf("ret = %d\n",ret);
}
#endif
close(fd);
return 0;
}
-
这里涉及到了argc和argv的使用百度百科argc argv
argc代表的是变量的个数,是int型的,argv是一个指针数组,v-vector,是char*型的专门用来放指向这些变量的指针变量的,
argc可以说包含两部分,第一部分是程序名或者程序运行的全路径名,这也算一个变量名
第二部分就是传进去的变量了,所以从argc[0]----程序名,argc[1]------传进去的第一个变量……以此类推,argv[0]、argv[1]……也是以此对应来理解。 -
下面一部分代码是课件的,他把计算部分封装成了一个函数
int cal_len(const char *pathname)
{
int fd = -1; // fd 就是file descriptor,文件描述符
int ret = -1;
// 第一步:打开文件
fd = open(pathname, O_RDONLY);
if (-1 == fd) // 有时候也写成: (fd < 0)
{
//printf("\n");
perror("文件打开错误");
// return -1;
return -1;
}
//else
//{
//printf("文件打开成功,fd = %d.\n", fd);
//}
// 此时文件指针指向文件开头
// 我们用lseek将文件指针移动到末尾,然后返回值就是文件指针距离文件开头的偏移量,也就是文件的长度了
ret = lseek(fd, 0, SEEK_END);
return ret;
}
int main(int argc, char *argv[])
{
int fd = -1; // fd 就是file descriptor,文件描述符
int ret = -1;
if (argc != 2)
{
printf("usage: %s filename\n", argv[0]);
_exit(-1);
}
printf("文件长度是:%d字节\n", cal_len(argv[1]));
return 0;
}
- 注意传参的形式对应,char*的话就要传char *,open了之后记得最后close (fd),它这里没有写。
用lseek构建空洞文件
原理就是利用lseek的SEEK_SET,把文件指针移动到当前位置加上你设置的offset位置的和的位置,一般open一个文件的时候,没有特殊设置,文件指针都会在最前面。例如这时候offset设置10,然后再write一次的话,中间就有一段10个字节的空洞位置,也就是构建了一个空洞文件。
lseek(fd, 10, SEEK_SET);
引用课上的说法,空洞文件的方法对多线程共同操作文件极其有用,就像以前flashget那样下载,有一个一个下载点,最终连成一片那样。