Linux系统编程篇—文件IO(文件来源、文件访问)

一、文件的来源

1、磁盘、Flash、SD卡、U盘
这些来源是真实存在的文件,以FAT32,EXT4,…等格式保存在某个设备上(如/dev/sda1),要使用mount指令挂载才能使用。

df -T//文件系统类型在Type列输出。只可以查看已经挂载的分区和文件系统类型。

在这里插入图片描述
2、Linux内核提供的虚拟文件系统,使用时也需要mount指令挂载才能使用。
在这里插入图片描述
3、特殊文件:/dev/下的文件,这些文件是一些设备结点,我们通过open、write操作它们时,通过驱动操作的是硬件。
Linux系统编程篇—文件IO(文件来源、文件访问)_第1张图片
主设备号用来确定哪一个驱动程序,次设备号用来确认哪一个硬件。
如:
一块开发板里IIC设备的主设备号都是89,但IIC1、IIC2的次设备号不同。
Linux系统编程篇—文件IO(文件来源、文件访问)_第2张图片

二、文件的访问

对于访问LInux文件有两种方法:1、通用的API访问。2、不通用的API访问

通用的 IO 模型:open/read/write/lseek/close
/*open*/
int open(const char *pathname,int flags);/*pathname:指向文件路径的指针;flags:文件权限*/
int open(const char *pathname,int flags,mode_t mode);/*pathname:指向文件路径的指针;flags:文件权限;mode:创建模式*/
/*成功:返回文件描述符*/

/*write*/
ssize_t write(int fd,const void *buf,size_f count);/*fd:文件描述符*/
/*成功:返回写入字节的个数(一个整型数)失败:返回-1;*/

/*read*/
ssize_t read(int fd,const void *buf,size_f count);/*fd:文件描述符;buf:接收的buf;count:读出了多少长度的字节*/
/*成功:返回读取字节的个数(一个整型数)失败:返回-1;*/

/*lseek*/
off_t lseek(int fd, off_t offset, int whence);/*fd:文件描述符;offset:对于whence的偏移值;whence:固定点位置*/
/*成功完成后,lseek()返回相应的偏移量从文件开始的字节数。利用这个特性可以计算文件的大小*/
 
/*close*/
int close(int fd);/*fd:文件描述符*/
/*返回值:成功返回0,出错返回-1并设置errno*/

API参数的详细解析:
Linux系统编程篇—文件编程(一)打开及创建、写入、读取
Linux系统编程篇—文件编程(二)光标移动(lseek)

不是通用的函数:ioctl/mmap

ioctl(input/output control)是一个专用于设备输入输出操作的系统调用,该调用传入一个跟设备有关的请求码,系统调用的功能完全取决于请求码。举个例子,CD-ROM驱动程序可以弹出光驱,它就提供了一个对应的Ioctl请求码。设备无关的请求码则提供了内核调用权限。

ioctl

ioctl是设备驱动程序中对设备的I/O通道进行管理的函数。所谓对I/O通道进行管理,就是对设备的一些特性进行控制,例如串口的传输波特率、马达的转速等等。
函数原型:

int ioctl(int fd, ind cmd,);/*fd:文件标示符,cmd:用户程序对设备的控制命令;后面的省略号:那是一些补充参数,一般最多一个,这个参数的有无和cmd的意义相关。*/

函数说明:
① fd 表示文件描述符;
② request 表示与驱动程序交互的命令,用不同的命令控制驱动程序输出我们需要的数据;
③ … 表示可变参数 arg,根据 request 命令,设备驱动程序返回输出的数据。 ④ 返回值:打开成功返回文件描述符,失败将返回-1。

ioctl 的作用非常强大、灵活。不同的驱动程序内部会实现不同的 ioctl,APP 可以使用各种 ioctl 跟驱动程序交互:可以传数据给驱动程序,也可以从驱动程序中读出数据。

mmap

mmap将一个文件或者其它对象映射进内存。文件被映射到多个页上,如果文件的大小不是所有页的大小之和,最后一个页不被使用的空间将会清零。mmap在用户空间映射调用系统中作用很大。
函数原型:

void* mmap(void* start,size_t length,int prot,int flags,int fd,off_t offset);

函数说明:
① addr 表示指定映射的內存起始地址,通常设为 NULL 表示让系统自动选定地址,并在成功映射后返回该
地址;
② length 表示将文件中多大的内容映射到内存中;
③ prot 表示映射区域的保护方式,可以为以下 4 种方式的组合
  a. PROT_EXEC 映射区域可被执行
  b. PROT_READ 映射区域可被读出
  c. PROT_WRITE 映射区域可被写入
  d. PROT_NONE 映射区域不能存取
④ Flags 表示影响映射区域的不同特性,常用的有以下两种
  a. MAP_SHARED 表示对映射区域写入的数据会复制回文件内,原来的文件会改变。
  b. MAP_PRIVATE 表示对映射区域的操作会产生一个映射文件的复制,对此区域的任何修改都不会写回 原来的文件内容中。
⑤ 返回值:若成功映射,将返回指向映射的区域的指针,失败将返回-1。

三、文件IO项目实战——cp函数的实现

程序流程图:
Linux系统编程篇—文件IO(文件来源、文件访问)_第3张图片
(1)使用通用的 IO 模型(open/read/write/lseek/close)实现cp函数

#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc,char **argv)
{
	int old_fd=0;
	int new_fd=0;
	long int r_len=0;
	long int w_len=0;
	char buf[1024]={'\0'};
	int cnt =1;
	/*1、输入判断*/
	if(argc!=3){
		printf("input is error!\n");
		printf("format:%s  \n",argv[0]);
		return -1;
	}
	/*2、打开老文件*/
	old_fd=open(argv[1],O_RDONLY);
	if(old_fd==-1){
		printf("open %s failure\n",argv[1]);
		return -1;
	}
	printf("open %s success\n",argv[1]);
	/*3、打开新文件*/
	new_fd=open(argv[2],O_WRONLY|O_CREAT,0600);
	if(new_fd==-1){
		printf("open %s failure\n",argv[2]);
		return -1;
	}
	printf("open %s success\n",argv[2]);
	/*4、写入数据*/
	while((r_len=read(old_fd,buf,1024))>0){
		printf("read success %d\n",cnt);
		printf("read data %ld\n",r_len);

		w_len=write(new_fd,buf,r_len);
		if(w_len!=r_len){
			printf("write data error !\n");
			return -1;
		}
		printf("write success %d\n",cnt++);
		printf("write data:%ld\n",w_len);
	}
	/*5、关闭文件*/
	close(old_fd);
	close(new_fd);
	return 0;
}

(2)使用非通用的 IO 模型(ioctl/mmap)实现cp函数

#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc,char **argv)
{
	int old_fd=0;
	int new_fd=0;
	long int r_len=0;
	long int w_len=0;
	char *buf;
	struct stat stat;

	/*1、判断参数*/
	if(argc!=3){
		printf("input is error!\n");
		printf("format:%s  \n",argv[0]);
		return -1;
	}
	/*2、打开原文件*/
	old_fd=open(argv[1],O_RDONLY);
	if(old_fd==-1){
		printf("open %s failure\n",argv[1]);
		return -1;
	}
	/*3、确定老文件的大小*/
	if(fstat(old_fd,&stat)==-1){
		printf("can not get stat of file %s\n",argv[1]);
		return -1;
	}
	printf("old file have %ld data\n",stat.st_size);
	/*4、映射老文件*/
	buf=mmap(NULL,stat.st_size,PROT_READ, MAP_SHARED,old_fd,0);
	if(buf == MAP_FAILED){
		printf("mmap fail\n");
		return -1;
	}
	/*5、创建新文件*/
	new_fd=open(argv[2],O_WRONLY|O_CREAT,0600);
	if(new_fd==-1){
		printf("open %s failure\n",argv[2]);
		return -1;
	}
	printf("open %s success\n",argv[2]);
	w_len=write(new_fd,buf,stat.st_size);
	printf("write data:%ld\n",w_len);

	close(old_fd);
	close(new_fd);
	return 0;
}

注:此处获取文件大小使用了一个fstat函数,详情参照:C语言用fstat函数获取文件的大小

你可能感兴趣的:(Liunx系统编程篇,linux,嵌入式,文件)