open、creat、write、close、lseek等文件操作函数详解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/baidu_37964071/article/details/79658091

首先我们回忆一下,stdin&stdout&stderr

C默认会打开三个输出输入流,分别是stdin,stdout,stderr。且这三个流的类型都是FILE*,fopen返回值类型,文件指针

文件操作

文件操作的一般过程:

打开文件,打开成功后,应用程序将获得文件描述符;

应用程序使用文件描述符对文件进行读写等操作;

全部操作完毕后,应用程序需要将文件关闭以释放用于管理打开文件的内存;

、open和openat函数:系统调用可以打开或创建一个文件

1、看一下open函数:

(图中create函数在下面讲解)
参数说明:
pathname:指向欲打开的文件路径字符串

flags :打开文件时,可以传入多个参数选项,用下面的一个或者多个常量(只列出了一部分)进行“或”运算,构成flags.(如下)

注:open函数具体使用那个,和具体场景有关。比如,目标文件不存在,需要open创建,则第三个参数表示文件的默认权限(默认权限请看文章第三点对umask的介绍点击打开链接)。

否则就使用两个参数即可。

返回值:

成功:新打开的文件描述符

失败:-1
2、看一下openat函数


可以看出来,参数dirfd将open函数和openat函数区分开来,共有三种可能性:
(1)path参数指定的是绝对路径名,在这种情况下,fd参数被忽略,openat函数相当于open函数
(2)path参数指定的是相对路径名,fd参数指出了相对路径名在文件系统中的开始地址。
fd参数是通过打开相对路径名所在的目录来获取。
(3)path参数指定了相对路径名,fd参数具有特殊值AF_FDCWD。在这种情况下,路径名在当前工作目录中获取,openat函数在操作上与open函数类似。

所以,openat函数是希望解决两个问题:
(1)让线程可以使用相对路径名打开目录中的文件

(2)可以避免time-of-check-of-use(TOCTTOU)错误。

二、函数creat-创建一个新文件

见上图open。
此函数等效于:
open(path,O_WRONLY|O_CREAT|O_TRUNC,mode);

因为creat函数是以只写方式打开所创建的文件。

、read函数:系统调用从打开的文件中读取数据

如下:

 

参数:
fd:要读取的文件的描述符。
buf:读取到的数据要放入的缓冲区。
count:要读取的字节数。
返回值:
若成功返回读到的字节数,若已到文件结尾则返回0
若出错则返回-1并设置变量errno的值。
(注意:1. 这里的size_t是无符号整型,ssize_t是有符号整型。2. buf指向的内存空间必须事先分配好)

会由多种情况使实际读到的字节数少于要求读的字节数:

(1)读普通文件时,在要求读到的字节数之前已达到了文件尾端。
(2)当从终端设备读时,通常一次只能读一行
(3)当从网络读时,网络中的缓冲机制可能造成返回值小于所要求读的字节数。
(4)当从管道或FIFO读时,如若管道包含的字节少于所需的数量,那么read只能返回实际可用的字节数。
(5)当从某些面向记录的设备(如磁带),一次最多返回一个记录。

、write:系统调用向打开的文件写数据

如下:

参数:
fd:要写入的文件的描述符。
buf:要写入的数据所存放的缓冲区。
count:要写入的字节数。
返回值:
若成功返回已写的字节数
出错则返回-1并设置变量errno的值
write出错的一个常见原因是磁盘已写满,或者超出了一个给定进程的文件长度限制。
对于普通文件,写操作从文件的当前偏移量处开始。如果在打开该文件时,指点了O_APPEND选项,则在每次写操作之前,将文件偏移量设置在文件的当前结尾处,在一次成功写之后,该文件偏移量增加实际写的字节数。

、close:系统调用关闭一个打开的文件。

参数:
fd:要关闭的文件的描述符。
返回值:若成功返回0
出错则返回-1
注:当一个进程终止时,内核会自动关闭它所有打开的文件

、lseek:系统调用可以改变文件偏移量(File Offset)。
文件偏移量是一个整数,表示距文件起始处的字节数

参数whence必须是以下三个常量之一:
SEEK_SET:将文件偏移量设置在距文件开始处offset个字节。
SEEK_CUR:将文件偏移量设置在其当前值加offset,offset可正可负。
SEEK_END:将文件偏移量设置为文件长度加offset,offset可正可负。

若成功,则返回新的文件偏移量。若出错,返回-1。

注意:通常,文件的当前偏移量应当是一个非负整数,但是,某些设备也可能允许负的偏移量。但对于普通文件,其偏移量必须是非负值。
因此在比较lseek的返回值时不要测试其是否小于0,而要测试它是否等于-1。

lseek仅将当前的文件偏移量记录在内核中,它并不引起任何I/O操作。然后,该偏移量用于下一个读或写操作。
文件偏移量可以大于文件的当前长度,在这种情况下,对该文件的下一次写将加长该文件,并在文件中构成一个空洞,这一点是允许的。位于文件中但没有写过的字节都被读为0。
文件中的空洞并不要求在磁盘上占用存储区。

eg:
1、hellow.c 写文件
1 #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<sys/stat.h>
  4 #include<fcntl.h>
  5 #include<unistd.h>
  6 #include<string.h>
  7 
  8 int main(){
  9     umask(0);
 10     int fd=open("myfife",O_WRONLY|O_CREAT,0644);
 11     if(fd<0){
 12         perror("open");
 13         return 1;
 14     }
 15 
 16     int count=5;
 17     const char *msg="hello bit!\n";
 18     int len=strlen(msg);
 19 
 20     while(count--){
 21         write(fd,msg,len);
 22     }
 24     close(fd);
 25     return 0;
 26 }
    

结果,新建了文件myfife且写入成功

2、hellor.c读文件
 1 #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<sys/stat.h>
  4 #include<fcntl.h>
  5 #include<unistd.h>
  6 #include<string.h>
  7 
  8 int main(){
  9     int fd=open("myfife",O_RDONLY);
 10     if(fd<0){
 11         perror("open");
 12         return 1;
 13     }
 14 
 15     const char *msg="hello bit!\n";
 16     char buf[1024];
 17 
 18     while(1){
 19         ssize_t s=read(fd,buf,strlen(msg));
 20         if(s>0){
 21             printf("%s",buf);
 22         }else{
 23             break;
 24         }
 25     }
 26 
 27     close(fd);
 28     return 0;
 29 }


结果:将刚写入的文件读出:


阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页