欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2024-02-26 14:44:04
...

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

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

文件操作

文件操作的一般过程:

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

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

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

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

1、看一下open函数:

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

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

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

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

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

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

返回值:

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

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

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

可以看出来,参数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函数:系统调用从打开的文件中读取数据

如下:

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

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

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

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

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

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

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

open、creat、write、close、lseek等文件操作函数详解
参数:
fd:要关闭的文件的描述符。
返回值:若成功返回0
出错则返回-1
注:当一个进程终止时,内核会自动关闭它所有打开的文件

、lseek:系统调用可以改变文件偏移量(File Offset)。
文件偏移量是一个整数,表示距文件起始处的字节数
open、creat、write、close、lseek等文件操作函数详解

参数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且写入成功

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

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 }


结果:将刚写入的文件读出:
open、creat、write、close、lseek等文件操作函数详解