前面的文章里面,仔细讲了在linux系统对文件的读写操作以及文件管理,为今天要讲的内容作了铺垫(如果您是刚接触这方面的内容,可以先看我之前写的文章,有错误的地方,还望指出来,在这里先说一声谢谢)。好了废话不多说,直接进入主题。
一、了解一下文件指针和文件流、流的概念:
1、文件流与流:流(stream)对应自然界的水流。文件操作中,文件类似是一个大包裹,里面装了一堆字符,但是文件被读出/写入时都只能一个字符一个字符的进行,而不能一股脑儿的读写,那么一个文件中N多的个字符被挨个一次读出/写入时,这些字符就构成了一个字符流。所以说流是动态的,不是静态的。所以编程中提到流这个概念,一般都是IO相关的。所以经常叫IO流。文件操作时就构成了一个IO流(文件流)。文件流很长,里面有很多个字节。那我们当前正在操作的是哪个位置?GUI(图形用户界面)模式下的软件用光标来标识这个当前正在操作的位置,这是给人看的。(光标就好像在我们的这个流里面打了一个截点,光标就是在我们的这个流里来回的动的)
2、文件指针:当我们要对一个文件进行读写时,一定需要先打开这个文件,所以我们读写的所有文件都是动态文件。动态文件在内存中的形态就是文件流的形式。在内存里的动态文件中,我们会通过文件指针来表征这个正在操作的位置。所谓文件指针,就是我们文件信息管理表vnode这个结构体里面的一个指针。(所以文件指针其实是vnode中的一个元素,这个在我上一篇文件系统文章里面有很详细的介绍)这个指针表示当前我们正在操作文件流的哪个位置。这个指针不能被直接访问,linux系统用lseek函数来访问这个文件指针——当我们打开一个空文件时,默认情况下文件指针指向文件流的开始。所以这时候去write时写入就是从文件开头位置开始的。write和read函数本身自带移动文件指针的功能,所以当我write了n个字节后,(文件指针会自动依次向后移动n位。)如果需要人为的随意更改文件指针(让光标随意移动),自由化,那就只能通过lseek函数了;而且我们前面学的read和write函数都是从(当前文件指针处)开始操作的,所以当我们用lseek显式的将文件指针移动后,那么再去read/write时就是从(移动过后的位置)开始的。但是文件中的内容还是完整存在的。
二、从man手册来说lseek函数:
1、还是那句话,在linux系统下有问题,找男人(man手册),哈哈哈哈。我们来看一下所查的结果如下(其实这里不要看别人写的代码里头文件那么多,用man手册一查就可以查到所用的函数被包含在哪个头文件里,然后直接复制粘贴过就可以用了,看起来非常有逼格,哈哈哈。):
这里我们可以看到:
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
参数 offset(偏移)的含义取决于参数 whence(根源,从何处):
1) 如果 whence 是 SEEK_SET,则返回的文件偏移量将被设置为 offset。
2.)如果 whence 是 SEEK_CUR,则返回的文件偏移量将被设置为 cfo(当前文件偏移量(current file offset)) 加上 offset(偏移量), offset 可以为正也可以为负。
3.)如果 whence 是 SEEK_END,则返回的文件偏移量将被设置为文件长度加上 offset,offset 可以为正也可以为负。
a、 欲将读写位置移到文件开头时:
lseek(int fildes,0,SEEK_SET);
b、欲将读写位置移到文件尾时:
lseek(int fildes,0,SEEK_END);
c、想要取得目前文件位置时:
lseek(int fildes,0,SEEK_CUR);
返回值类型off_t :
当调用成功时则返回目前的(读写位置),也就是距离文件开头多少个字节。若有错误则返回-1,errno 会存放错误代码。
代码示例:https://github.com/1121518wo/linux-/blob/master/文件偏移量代码示例
演示效果:
这里可以看到从文件开头起偏移量为3,把原文件内容前三个字母给遮住了。
2、用lseekh函数计算文件长度:
1)linux中并没有一个函数可以直接返回一个文件的长度(因为不需要)。但是我们实际使用时经常会需要知道一个文件的长度,怎么办?(我们可以利用lseek来写一个函数得到文件长度即可。)原理就是当我们新打开一个文件时,此时文件指针在文件最开头处,我们用lseek函数把文件指针移动到文件末尾处,然后返回值就是我们文件的末尾指针距离文件开头的偏移量,即文件的长度。代码示例:
https://github.com/1121518wo/linux-/blob/master/文件长度代码示例
演示效果:
3、用lseek构建空洞文件:
1)什么是空洞文件?
通俗的讲就是一个文件里面有一段是空(其实这里的空洞文件时是指文件指针所指位置,也就是文件偏移量超出文件末尾了);而普通文件中间是不能有空的,因为我们write时文件指针是依次从前到后去移动的,不可能绕过前面直接到后面(我们打开一个文件后,用lseek往后跳过一段,再write写入一段,就会构成一个空洞文件(这个空洞文件就是有一段没有内容。)。可以看官方对空洞文件的解释:
3)注意:这里的空洞文件,在后面往文件里面写数据,会被文件系统看成”做为返回值(”表示空字符,不计入内存中),所以返回读取的内容为0,这也就能够解释为什么空洞这段空间写的数据并不会修改文件的大小。
代码示例:https://github.com/1121518wo/linux-/blob/master/空洞文件示例https://github.com/1121518wo/linux-/blob/master/空洞文件示例
https://github.com/1121518wo/linux-/blob/master/空洞文件示例
演示效果:
2、空洞文件方法对多线程共同操作文件是及其有用的。有时候我们创建一个很大的文件(比如视频文件),如果从头开始依次构建时间很长。有一种思路就是将文件分为多段,然后多线程来操作每个线程负责其中一段的写入。(就像修100公里的高速公路,分成20个段来修,每个段就只负责5公里,就可以大大提高效率)。
转载请注明:XAMPP中文组官网 » linux系统下lseek函数的详细用法