IO操作之文件IO

前言

在进行Linux嵌入式开发的过程中,我们会接触到一系列与IO操作相关的函数。一般而言,我们将其分为三类,分别是:
文件IO标准IO库函数
其中,文件IO顾名思义便是对文件进行操作的函数,再加上在Linux系统中,一切皆文件,所以当我们在之后的时间内进行更加深入的学习之后,文件IO的操作函数将会使用的越来越多。所以,今天,我们首先从将从常见的文件IO函数开始进行学习。

open函数

概述

open函数的作用是打开一个文件,该函数的形式如下:

int open(const char *pathname, int flags, mode_t mode)
函数原型int open(const char *pathname, int flags, mode_t mode)
头文件<sys/types.h> <sys/stat.h> <fcntl.h>
参数含义如下
返回值成功:返回一个大于2的文件描述符 失败:返回 -1

参数pathname是一个常量指针,即该指针指向的内容是一个只读的数据,即需要打开的文件的文件名,参数flags指的是打开该文件的方式,比如:以只读方式打开、以追加方式打开等,常见的打开方式如下:

O_RDONLY  以只读方式打开文件
O_WRONLY  以只写方式打开文件
O_RDWR	  以读写的方式打开文件
O_CREAT	  创建一个文件,如果文件不存在,则新建一个,否则将报错
O_APPEND  以追加的方式打开文件,即向文件写入新的内容时,不覆盖文件中之前的内容
O_TRUNC  向文件写入新的内容时,覆盖文件中之前的内容
更为详细的文件打开方式,可以利用man 2 open命令,在linux系统中进行了解。

参数mode指的是当利用O_CREAT新建一个文件时,需要指定该文件的访问权限r(读)w(写)x(执行),我们使用一个八进制的数指定文件的权限,但是在实际应用中,该权限的设定并非文件最终的权限,而是与文件的掩码umask(在Linux系统的命令行中输入umask,可以查看umask的值)有关,文件最终的权限是指定的权限与取反后的掩码进行相与之后的结果。
比如:如果掩码值是0022(第一个0是八进制数的标志,第二个0是针对文件所有者的掩码,第一个2是针对用户组的掩码,第二个2是针对其他用户的掩码),而我们在open函数中指定文件的权限为0777,那么,该文件的最终权限为:0777 & (~(0022)) = 755

测例

//利用open函数新建一个权限为755的文件
int fd = 0;//存储open函数返回的文件描述符信息
fd = open("./a.c",O_CREAT|O_RDWR,0777);//在当面路径下,新建一个可读可写的新文件a.c

文件的新建结果:
在这里插入图片描述

write函数

概述

write函数的作用是向打开的文件中写入数据,函数的形式如下:

ssize_t  write(int  fd,  const  void  *buf,  size_t count);
函数原型ssize_t write(int fd, const void *buf, size_t count)
头文件<unistd.h>
参数含义如下
返回值成功:返回向文件中写入的数据数量:返回 -1

参数fd即open函数的返回值文件描述符,参数buf即需要向文件中写入的内容,参数cout指的是希望向文件中写入的数据的数量。值得注意的是,该函数的返回值与count是相等的(区别于下面的read函数),但是如果指定希望写入的数据量大于写入的数据的实际长度时,将产生数组越界,这是程序员应该避免的操作。

测例

//向上述的a.c文件中写入一个字符串,内容为:I love china
char* write_buf = "I love China\n";//需要向文件中写入的内容
write(fd,write_buf,strlen(write_buf));

程序运行结果:
在这里插入图片描述

read函数

read函数的作用是从打开的文件中读取数据,函数的形式如下:

 ssize_t read(int fd, void *buf, size_t count);
函数原型ssize_t read(int fd, void *buf, size_t count)
头文件<unistd.h>
参数含义如下
返回值成功:返回从文件中读取到数据的实际数量:返回 -1

与write函数一样,参数fd指的是利用open函数打开的文件的文件描述符,而参数count则是用户希望从文件读取的数据数量,且不同于write函数,count参数与read函数的返回值可以不同。

测例

 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <stdio.h>
 #include <string.h>
 int main()
 {
     int fd = 0;
     char read_buf[128] = {0};
     fd = open("./a.c",O_CREAT|O_RDWR,0777);
     read(fd,read_buf,128);
     printf("read_buf = %s",read_buf);
     close(fd);
    return 0;
 }

输出结果为:
在这里插入图片描述

lseek函数

lseek函数的作用是指定文件指针的位置,函数的形式如下:

off_t lseek(int fd, off_t offset, int whence);
函数原型off_t lseek(int fd, off_t offset, int whence)
头文件<sys/types.h> <unistd.h>
参数含义如下
返回值成功:返回文件指针的当前指定的位置:返回 -1

参数fd与其他函数一样,也是open函数打开文件的文件描述符;参数offset则是文件指针的偏移位置,如果该参数为正数,那么便将文件指针向后移动,如果该参数为负数,则表示将文件指针向前移动,如果是0,则表示不进行移动;参数whence便是指定从哪个位置开始进行偏移,可选的参数为:

SEEK_SET---表示文件的开头
SEEK_CUR---表示当前位置
SEEK_END---表示文件结尾

值得注意的是,当我们打开一个文件时,文件指针默认指向文件的开头,但是当我们向一个新文件写入数据之后,文件指针便指向了文件的结尾,所以如果此时立即对文件中的内容进行读取,那么将读取不到任何内容。只有重新修改文件指针的位置之后,才能读到希望读取的数据。

测例

 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <stdio.h>
 #include <string.h>
 int main()
 {
     int fd = 0;
     unsigned int numOfData = 0;
     char read_buf[128] = {0};
     char write_buf[] = "I love China very much!";
     fd = open("./a.c",O_CREAT|O_RDWR,0777);
     numOfData = write(fd,write_buf,sizeof(write_buf)/sizeof(write_buf[0]));
     read(fd,read_buf,numOfData);//立即读取文件中的内容
    printf("first read_buf = %s\n",read_buf);
    lseek(fd,0,SEEK_SET);//将文件指针的位置设置为文件开头
    read(fd,read_buf,128);
    printf("second read_buf = %s\n",read_buf);
    close(fd);
    return 0;
 }

输出结果如下:
在这里插入图片描述

close函数

close函数的作用是关闭一个打开的文件,需要注意的是,当使用open函数打开一个文件之后,必须在合适的地方利用close函数关闭该文件。函数的形式如下:

int close(int fd);
函数原型int close(int fd)
头文件<unistd.h>
参数含义如下
返回值成功:返回0:失败:返回 -1

参数fd与前面的含义相同。
当我们在程序中使用open函数打开一个文件之后,一定记住在相应的地方利用close函数进行关闭操作!

综合训练

我们需要知道的是,Linux中的所有shell命令都是利用函数实现的。所以,我们也可以自己利用函数实现Linux中的相关命令。此处,我们就利用上述四个函数,实现Linux的文件拷贝命令:cp。
该命令的格式如下:

cp 源地址源文件 目标地址目标文件

代码如下:

 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <stdio.h>
 int main(int argc,char* argv[])
 {
 	int src_fd = 0;//源文件文件描述符
 	int dst_fd = 0;//目标文件文件描述符
 	char read_buf[128] = {0};//从源文件读取到的数据
 	char* write_buf = "I love China ver much!\n";
 	ssize_t numOfData = 0; 
 	src_fd = open(argv[1],O_RDWR);//以只读的方式打开源文件
 	if(src_fd < 0)//打开文件失败
 	{
 		printf("打开源文件失败!\n");
 		return -1;
 	}
 	write(src_fd,write_buf,sizeof(write_buf) / sizeof(write_buf[0]));
 	close(src_fd);
 	if(argc < 3)//需要输入三个参数
 	{
 		printf("参数输入有误!\n");
 		return -1;
 	}
 	src_fd = open(argv[1],O_RDONLY);//以只读的方式打开源文件
 	if(src_fd < 0)//打开文件失败
 	{
 		printf("打开源文件失败!\n");
 		return -1;
 	}
 	dst_fd = open(argv[2],O_CREAT | O_RDWR,0777 );//以读写的方式打开源文件
 	if(dst_fd < 0)//打开文件失败
 	{
 		printf("打开目标文件失败!\n");
 		return -1;
 	}
 	while(1)//从源文件中读取数据并写入目标文件中
 	{
 		numOfData = read(src_fd,read_buf,128);
 		write(dst_fd,read_buf,numOfData);
 		if(numOfData < 128)
 		{
 			break;
 		}
 	}
 	printf("文件拷贝成功");
 	close(src_fd);
 	close(dst_fd);
 }

注意事项

上述的四个函数,当返回值为**-1**时,均表示该函数的使用出现了错误。

补充:文件描述符

Linux系统有三个默认的文件描述符,是其他文件不能够使用的,其中:

0:标准输入  宏定义:STDIN_FILENO
1:标准输出  宏定义:STDOUT_FILENO
2:标准错误  宏定义:STDERR_FILENO

所以,利用上述open函数打开文件的文件描述符都是从3开始的。

总结

由于本人能力有限,本文难免有疏漏和错误之处,还望各位读者能够不吝指正。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值