Linux应用编程学习记录(三)

  1.  lseek函数

        前两次已经学过了write和read函数,这两个函数在使用中可能存在对同一个文件多次操作的问题,因此不得不关注读写的起点是哪儿。假设有这么一个需求:一个文件中有6个字符,打开文件后我希望直接读取第4个字符,这怎么办?显然直接读取是不行的了,你得移动读写起点。

        lseek函数就是为这个需求而生的。

A)返回值为长整型,代表设置后的读写起点。是从文件开头开始算起的偏移字节数,当为0时代表就是文件开头。显然这个数字不应该小于0。一旦返回-1则代表执行函数出错。

B)第一个参数是文件句柄

C)第二个参数是偏移量,它的含义取决于第三个参数。正数代表往后移动,负数代表往前移动。

D)第三个参数是偏移量的参考点。有三个取值

SEEK_SET  读写偏移量以文件开头为参考

SEEK_CUR  读写偏移量以当前所在位置为参考

SEEK_END  读写偏移量以文件末尾为参考

E)读和写的起点是共用的,改变了读的位置,意味着写的位置也改了。

F)写操作是覆盖进行的。比如一个文件中原来有6个字符:abcdef,当移动光标到第四个位置,再写入abc,会发现结果为abcdabc

 

2.  补充一个知识点

        我们把这种借助lseek函数,实现随心所欲读写文件任意位置的操作叫做随机读写;那么那种按部就班从头开始读写的操作就叫做顺序读写。

        在Linux中并非所有文件都可以随机读写,有不少文件只能顺序读写。那么该怎么判断呢?

        还是要借助lseek函数。像这样调用:

        offset=lseek(fd, 0, SEEK_CUR);

        因为偏移量写着0,而参考起点是当前位置,那等于没有移动。因此这个函数完完全全就是试探,如果返回值是-1,那说执行失败。因此你操作的这个文件不允许调整读写位置。

 

3.  所谓文件的读写起点和文件末尾到底指的是哪?

        lseek函数涉及到很多偏移量、参考位置这样的东西。看起来很简单,却很容易出现错一位的情况,让人十分挠头。不如来个图,把这些关系好好捋一捋,假设现在有一个文件,内容是“hello, welcome to linux world!”这个字符串,一共有30个字符,但是文件末尾会多出一个转义字符‘/0’。因此文件中一共有31个字符。

A)首先我们要明确一点,像下面这样使用lseek函数可以计算出当前的读写位置(因为它以当前的读写位置为参考,无偏移,直接返回,那不就等于返回的就是当前的读写位置嘛)

                               lseek(fd, 0, SEEK_CUR);

当我们第一次打开文件,立即执行上面的函数时,会发现结果是0而不是1。如果我们把读写位置理解成指向字符的箭头,读写位置是几,就代表指向的是第几号字符。那么对字符的标号,就必须是从0开始的!

        按照这个约定,今后我说文件的读写位置在9号位置时,其实我指的是实际意义上的第10个字符。反过来,如果我想读取world这个字符时,我首先知道w是实际意义上的第25个字符,那么它的标号其实是24,于是我只需要把读写位置调到24就行了。

        注意:上述提到的几号位,都是从文件开头开始算起的。如果从文件末尾开始算起,显然就是另一回事了。见下面的分解。

B)还是对例子中的文件进行试验,当我执行下面这个函数时:

          lseek(fd, 0, SEEK_END);

返回值是31。从函数的参数配置上来解释:以文件末尾为起点,无偏移,直接返回读写位置。那么就等于直接返回文件末尾的读写位置咯。现在这个数值是31,代表实际意义上的第32个字符,但我们心理都清楚,其实文件中只有31个字符。因此文件末尾的读写位置,其实指的是最后一个真实字符的后一个byte位。

        当然,像上面这样调用函数,是可以用来计算文件中到底有多少真实字符的,包括末尾的'\0'。

 

4.  lseek函数使用体验

A)先来个例子

        假设现在我用lseek函数计算当前的读写位置,返回值是7。而我想读取linux这5个字符,我该怎么做?

三种思路:

其一,直接以文件开头为起点,调整读写位置。那么我数一数,发现linux的首字母是实际意义上的第19个字符,那么它的标号就是18。于是我就写  lseek(fd, 18, SEEK_SET);

其二,直接以文件结尾为起点,调整读写位置。那么我要确认这个位置从文件末尾数过来,需要数到几?

从上图可以看出,要数13次。于是我就写  lseek(fd, -13, SEEK_END);

其三,直接以当前的位置为起点,调整读写位置。那么我要数一数,从当前位置数到目标位置,需要数到几?

从上图可以看出,要数11次。于是我就写 lseek(fd, 11, SEEK_CUR);

B)上述例子可以看出,要用好lseek函数,你得心理非常清楚SEEK_SET、SEEK_CUR和SEEK_END到底指向的是哪个字符(前面已经分析过)。同时你还必须非常清楚偏移量是多少,刚才的方法很原始,就是掰手指去数。

C)更多的时候,偏移量怎么能靠自己去数,实在是太low了。

其一,也许我们知道两个位置之间间隔了多少个字符。那么偏移量就是间隔的字符数+1。

其二,也许我们知道两个位置各自的标号。这个标号可能是从1开始也可能是从0开始。不过不重要,因为我们想知道的其实是二者之间的偏移。因此直接用二者的标号相减就行了。

 

5.  补充一个知识吧

        使用

hexdump -C 文件名

可以把文件中的数据以十六进制的形式打印出来,比如上面例子中提到的文件:

PS:这个文件是我手打的,发现最后一个位0a,对应换行符

 

6.  ioctl函数

这个函数没办法深究,是因为它不具备共通性。

                                   

        从教材上的描述可以看出来,这个函数有比较强的定制化色彩,主要应该针对设备文件的操作而言。这取决于驱动程序是怎么写的了。现在我暂时没心思去研究某个具体的驱动怎么写,因此这个函数就先放一放。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值