Linux文件IO_02

4.lseek函数详解

4.1lseek函数介绍

  • 当我们想要打开一个文件进行读写等操作时,文件被打开后动态文件在内存中的形态就是文件流的形式。文件流很长,里面有很多个字节。GUI模式下的软件(比如notepad++)用光标来标识当前正在操作的位置。而在动态文件中,文件指针可以表征这个当前正在操作的位置。文件指针,就是我们文件管理表这个结构体里面的一个指针。它其实是vnode中的一个元素。这个指针表示当前我们正在操作文件流的哪个位置。这个指针不能被直接访问,linux系统用lseek函数来访问这个文件指针。
  • 当我们打开一个空文件时,默认情况下文件指针指向文件流的开始。所以这时候去write时写入就是从文件开头开始的。write和read函数本身自带移动文件指针的功能,所以write了n个字节后,文件指针会自动向后移动n位。如果需要人为的随意更改文件指针,那就只能通过lseek函数了。 read和write函数都是从当前文件指针处开始操作的,所以当用lseek显式的将文件指针移动后,再去read/write时就是从移动过后的位置开始的。

lseek函数原型:
lseek : reposition read/write file offset

#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);

其中fd参数是f一个已打开的文件描述符,offset为读写位置的位移数,这个位移数是根据参数whence来确定的,whence参数分为下列三种:

whence含义
SEEK_SET表示offset用来直接设置读写位置
SEEK_CUR表示以目前的读写位置往后增加offset个位移量
SEEK_END表示将读写位置指向文件尾后再增加offset个位移量

返回值是目前的读写位置,也就是距离文件开头多少个字节。若有错误则返回-1,errno会存放错误代码。
几个示例:
将读写位置移到文件开头:lseek(myfile, 0, SEEK_SET);
将读写位置移到文件尾:lseek(myfile, 0, SEEK_END);
想要取得目前文件位置:off_t cur=lseek(myfile, 0, SEEK_CUR);

4.2lseek实践:计算文件长度

利用lseek来写一个函数得到文件长度。
示例代码:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

int get_file_size(const char *file_path)
{
	int fd = -1;		
	int ret = -1;
	
	// step1: open file
	fd = open(file_path, O_RDONLY);
	if (fd==-1)
	{
		perror("file open error!");
		return -1;
	}
	else
	{
		printf("open success,fd = %d.\n", fd);
	}
	//step2:get size of file
	// 将lseek将文件指针移动到末尾,然后返回值就是文件的长度
	ret = lseek(fd, 0, SEEK_END);	
	return ret;
}

int main(int argc, char **argv)
{	
	char * file_path="./test.txt";
	printf("文件长度是:%d字节\n", get_file_size(file_path));
	return 0;
}

5.文件共享的实现

5.1文件共享概念

  • 文件共享就是同一个文件被多个独立的读写体(几乎可以理解为多个文件描述符)去同时操作。
  • 我们可以通过文件共享来实现多线程同时操作同一个大文件,以减少文件读写时间,提升效率。

5.2文件共享的3种实现方式

文件共享的核心就是怎么弄出来多个文件描述符指向同一个文件。
3种常见的文件共享情况:第一种是

  • 同一个进程中多次使用open打开同一个文件。
  • 在不同进程中去分别使用open打开同一个文件。
  • linux系统提供了dup和dup2两个API来让进程复制文件描述符。

分析文件共享时的核心关注点在于:分别写/读还是接续写/读

5.3文件描述符细节

  • 文件描述符本质上是进程表中文件描述符表的一个表项,进程通过文件描述符作为index去索引查表得到文件表指针,再间接访问得到这个文件对应的文件表。
  • 文件描述符这个数字是open系统调用内部由操作系统自动分配的,操作系统分配这个fd时也不是随意分配,也是遵照一定的规律的。操作系统规定,fd从0开始依次增加。fd也是有最大限制的,所以一个进程最多允许的文件文件个数就是这个。linux中文件描述符表是个数组(不是链表),所以这个文件描述符表其实就是一个数组,fd是index,文件表指针是value。
  • 当我们去open时,内核会从文件描述符表中挑选一个最小的未被使用的数字给我们返回。 fd中0、1、2已经默认被系统占用了,因此用户进程得到的最小的fd就是3了。 linux内核占用了0、1、2这三个fd是有用的,当我们运行一个程序得到一个进程时,内部就默认已经打开了3个文件stdin、stdout、stderr,这三个文件对应的fd就是0、1、2。。
  • 标准输入一般对应的是键盘(可以理解为:0这个fd对应的是键盘的设备文件),标准输出一般是LCD显示器(可以理解为:1对应LCD的设备文件)。 printf函数其实就是默认输出到标准输出stdout上了。stdio中还有一个函数叫fpirntf,这个函数就可以指定输出到哪个文件描述符中。

6.C语言标准库的文件IO介绍

常见的标准IO库函数有:fopen、fclose、fwrite、fread、fseek。

#include <stdio.h>
FILE *fopen(const char *path, const char *mode);
int fclose(FILE *stream);
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE*stream);
int fseek(FILE *stream, long offset, int whence);

文件IO就指的是open、close、write、read等API函数构成的一套用来读写文件的体系,这套体系可以很好的完成文件读写,但是效率并不是最高的。应用层的C语言库函数提供了一些用来做文件读写的函数列表,叫标准IO。标准IO由一系列的C库函数构成(fopen、fclose、fwrite、fread),这些标准IO函数其实是由文件IO封装而来的(fopen内部其实调用的还是open,fwrite内部还是通过write来完成文件写入的)。标准IO加了封装之后主要是为了在应用层添加一个缓冲机制,这样我们通过fwrite写入的内容不是直接进入内核中的buf,而是先进入应用层标准IO库自己维护的buf中,然后标准IO库自己根据操作系统单次write的最佳count来选择好的时机来完成write到内核中的buf(内核中的buf再根据硬盘的特性来选择好的实际去最终写入硬盘中)。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值