《Linux系统编程(第2版)》——2.7 用lseek()查找

2.7 用lseek()查找

一般情况下,I/O是线性的,由于读写引发的隐式文件位置更新都需要seek操作。但是,某些应用要跳跃式读取文件,需要随机访问而不是线性访问。lseek()系统调用能够将文件描述符的位置指针设置成指定值。lseek()只更新文件位置,没有执行其他操作,也并不初始化任何I/O:

lseek()调用的行为依赖于origin参数,该参数可以是以下任意值之一:

SEEK_CUR

将文件位置设置成当前值再加上pos个偏移值,pos可以是负值、0或正值。如果pos值为0,返回当前文件位置值。

SEEK_END

将文件位置设置成文件长度再加上pos个偏移值,pos可以是负值、0或正值。如果pos值为0,就设置成文件末尾。

SEEK_SET

将文件位置设置成pos值。如果pos值为0,就设置成文件开始。

调用成功时返回新的文件位置,错误时返回-1,并相应设置errno值。

举个例子,以下代码把fd的文件位置指针设置为1825:

下面是把fd的文件位置设置成文件末尾:

由于lseek()返回更新后的文件位置,可以通过SEEK_CUR,把偏移pos设置成0,确定当前文件位置:

到目前为止,lseek()调用最常见的用法是将指针定位到文件的开始、末尾或确定文件描述符的当前文件位置。

2.7.1 在文件末尾后查找
lseek()支持在文件末尾之后进行查找。例如,以下代码会定位到fd指向文件末尾之后的1688字节。

对这种用法本身而言,查找到文件末尾之后没什么意义——对该新的文件位置的读请求会返回EOF。但是,如果在该位置有个写请求,在文件的旧长度和新长度之间的空间会用0来填充。

这种零填充区间称为“空洞(hole)”。在UNIX系文件系统上,空洞不占用任何物理磁盘空间。这意味着文件系统上所有文件的大小加起来可以超过磁盘的物理大小。包含空洞的文件称为“稀疏文件(sparse file)”。稀疏文件可以节省很多空间,并提升性能,因为操作空洞不会产生任何物理I/O。

对文件空洞部分的读请求会返回相应的二进制0。

2.7.2 错误码
lseek()调用出错时,返回-1,并将errno值设置成如下四个值之一:

EBADF

给定的文件描述符没有指向任何打开的文件描述符。

EINVAL

origin的值不是设置成SEEK_SET、SEEK_CUR或SEEK_END,或者结果文件位置是负值。对于EINVAL,如果同时出现以上两种错误就太糟了。前者几乎可以肯定是个编译时错误,后者则是不太明显的运行时逻辑错误。

EOVERFLOW

结果文件偏移不能通过off_t表示。只有在32位的体系结构上才会发生这种错误。当前文件位置已经更新,该错误表示无法返回更新的值。

ESPIPE

给出的文件描述符和不支持查找操作的对象关联,比如管道、FIFO或socket。

2.7.3 限制
最大文件位置是受限于off_t类型的大小。大部分计算机体系结构定义该值为C long类型,在Linux上是指字长(word size)(即计算机的通用寄存器大小)。但是,内核在内部实现上是把偏移存储成C long long类型。这对于64位计算机没有什么问题,但是对于32位计算机,当执行查找操作时,可能会产生溢出EOVERFLOW的错误。

时间: 2024-08-08 16:25:22

《Linux系统编程(第2版)》——2.7 用lseek()查找的相关文章

《Linux系统编程(第2版)》——第1章 入门和基本概念 1.1 系统编程

第1章 入门和基本概念 摆在你面前的是一本关于系统编程的书,你将在本书中学习到编写系统软件的相关技术和技巧.系统软件运行在系统的底层,与内核和系统核心库进行交互.常见的系统软件包括Shell.文本编辑器.编译器.调试器.核心工具(GNU Core Utilities)以及系统守护进程.此外,网络服务.Web服务和数据库也属于系统软件的范畴.这些程序都是基于内核和C库实现的,可以称为"纯"系统软件.相对地,其他软件(如高级GUI应用),很少和底层直接交互.有些程序员一直在编写系统软件,而

《Linux系统编程(第2版)》——导读

前言 这本书是关于Linux上的系统编程."系统编程"是指编写系统软件,其代码在底层运行,直接跟内核和核心系统库对话.换句话说,本书的主题是Linux系统调用和底层函数说明,如C库定义的函数. 虽然已经有很多书探讨UNIX上的系统编程,却很少有专注于探讨Linux方面的书籍,而探讨最新版本的Linux以及Linux特有的高级接口的书籍更是凤毛麟角.此外,本书还有一个优势:我为Linux贡献了很多代码,包括内核及其上面的系统软件.实际上,本书中提到的一些系统调用和系统软件就是我实现的.因

《Linux系统编程(第2版)》——2.12 结束语

2.12 结束语 本章讨论了Linux系统编程的基础:文件I/O.在Linux这样遵循一切皆文件的操作系统中,了解如何打开.读.写和关闭文件是非常重要的.所有这些操作都是传统的UNIX方式,很多标准都涵盖它们.

《Linux系统编程(第2版)》——1.2 API和ABI

1.2 API和ABI 程序员都希望自己实现的程序能够一直运行在其声明支持的所有系统上.他们希望能在自己的Linux版本上运行的程序也能够运行于其他Linux版本,同时还可以运行在其他支持Linux体系结构的更新(或更老)的Linux版本上. 在系统层,有两组独立的影响可移植性的定义和描述.一是应用程序编程接口(Application Programming Interface,API),二是应用程序二进制接口(Application Binary Interface,ABI),它们都是用来定义

《Linux系统编程(第2版)》——1.4 Linux编程的概念

1.4 Linux编程的概念 本节给出了Linux系统提供的服务的简要概述.所有的UNIX系统,包括Linux,提供了共同的抽象和接口集合.实际上,UNIX本身就是由这些共性定义的,比如对文件和进程的抽象.管道和socket的管理接口等等,都构成了UNIX系统的核心. 本概述假定你对Linux环境很熟悉:会使用shell的基础命令.能够编译简单的C程序.它不是关于Linux或其编程环境的,而是关于Linux系统编程的基础. 1.4.1 文件和文件系统文件是Linux系统中最基础最重要的抽象.Li

《Linux系统编程(第2版)》——1.5 开始系统编程

1.5 开始系统编程 这一章着眼于Linux系统编程的基础概念并从程序员视角探索Linux系统.下一章将讨论基本的文件I/O,这当然包括读写文件,但是由于Linux把很多接口以文件形式实现,因此文件I/O的至关重要性不仅仅是对于文件而言,对于Linux系统的很多其他方面亦是如此. 了解了这些基础知识后,可以开始深入探索真正的系统编程了.我们一起动手吧.

linux系统编程之文件与I/O(六) fcntl函数与文件锁

一.fcntl函数 功能:操纵文件描述符,改变已打开的文件的属性 int fcntl(int fd, int cmd, ... /* arg */ ); cmd的取值可以如下: 复制文件描述符 F_DUPFD (long) 设置/获取文件描述符标志 F_GETFD (void) F_SETFD (long) 设置/获取文件状态标志 F_GETFL (void) F_SETFL (long) 获取/设置文件锁 F_GETLK F_SETLK,F_SETLKW 其中复制文件描述符可参见<linux系

LINUX系统编程 LINUX 虚拟内存

LINUX 虚拟内存 以32位操作系统为例子,因为64位系统虚拟地址过大为2^64,32位仅仅为2^32=4G更利于描述,但是原理东西都一样 这首先要从程序和进程之间的关系开始,我们一般写好一段C\C++代码编译后仅仅为可执行文件假设为a.out,我们 运行a.out的时候,这个才叫进程,进程是OS级别抽象的实体(PCB task_struct结构体),为程序运行进行各种检查和 系统资源分配,一个PCB包含部分信息如下: (摘至刑文鹏LINUX系统编程讲义) * 进程id.系统中每个进程有唯一的

《Linux系统编程(第2版)》——1.3 标准

1.3 标准 UNIX系统编程是门古老的艺术.UNIX编程的基础理念在几十年来一直根深蒂固.但是,对于UNIX系统,变化却是无处不在.各种行为不断变化,特性不断增加.为了使UNIX世界变得有序,标准化组织为系统接口定义了很多套官方标准.虽然存在很多这样的官方标准,但是Linux没有遵循任何一个标准.相反地,Linux致力于和两大主流标准兼容:POSIX和单一UNIX规范(Single UNIX Specification,SUS). 除了其他内容,POSIX和SUS为类UNIX操作系统定义了一套

《Linux系统编程(第2版)》——2.2 通过read()读文件

2.2 通过read()读文件 前面讨论了如何打开文件,现在一起来看如何读文件.在接下来的一节中,我们将讨论写操作. 最基础.最常见的读取文件机制是调用read(),该系统调用在POSIX.1中定义如下: 每次调用read()函数,会从fd指向的文件的当前偏移开始读取len字节到buf所指向的内存中.执行成功时,返回写入buf中的字节数:出错时,返回-1,并设置errno值.fd的文件位置指针会向前移动,移动的长度由读取到的字节数决定.如果fd所指向的对象不支持seek操作(比如字符设备文件),