【Linux学习笔记】文件相关系统调用接口

标签: 系统调用

我们在C语言中学习了很多文件相关的接口,如fopen,fclose,fwrite,fread等等。并且,C会默认打开三个输入输出流u,分别是stdin,stdout,stderr。这三个流的类型都是*FILE,文件指针。接下来我们看一下文件相关的系统调用接口,看看它和C语言的文件接口有什么关系。

文件相关系统调用接口

open
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
/*
pathname:要打开或创建的目标文件
flags:打开文件时,可以传入多个参数选项,用下面的一个或者多个常量进行“或”运算,构成flags。
参数:
    O_RDONLY:只读打开
    O_WRONLY:只写打开
    O_RDWR:读,写打开
    (这三个常量,必须指定一个且只能指定一个)
    O_CREAT:若文件不存在,则创建它,需要使用mode选项,来指明新文件的访问权限
    O_APPEND:追加写
返回值:
    成功:新打开的文件描述符
    关闭:-1
*/ 
close
#include <unistd.h>

int close(int fd);

/*
返回值:
    0表示关闭成功,-1表示关闭失败
*/
read
#include <unistd.h>

ssize_t read(int fd, void *buf, size_t count);
/*
fd:文件描述符
buf:读取的内容装到这里
count:读取文件的大小
返回值:    
     实际读取的字节数,0,表示读到文件结尾,-1,出错,
     实际读取的字节个数,并不一定等于count
*/
write
#include <unistd.h>

ssize_t write(int fd, const void *buf, size_t count);

/*    
buf:要想写出去的数据在哪里
count:数据的个数
返回值:返回实际写出去多少个字节
*/

C语言文件接口和文件系统调用接口的关系

我们看一个C文件接口写的代码:

#include <stdio.h>
#include <string.h>

int main( void )
{
    FILE *fp = fopen("myfile", "w");
    if(!fp)
    {
        printf("fopen error!\n");
    }

    const char *msg = "hello world\n";
    int count = 5;
    while(count--)  
    {
        fwrite(msg, strlen(msg), 1, fp);
    }

    fclose(fp);

    return 0;
}

再来看一个用系统调用接口写的代码:

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

int main()
{
    umask(0);
    int fd = open("myfile", O_WRONLY|O_CREAT, 0644);
    if(fd < 0)
    {
        perror("open");
        return 1;
    }

    int count = 5;
    const char *msg = "hello world!\n";
    int len = strlen(msg);

    while(count--)
    {
        write(fd, msg, len);
    }


    close(fd);
    return 0;
}

运行之后,发现这两个函数的功能是一模一样的,这说明什么问题呢?
要搞清楚这个问题之前那,我们先来认识两个概念:系统调用和库函数
- 库函数:fopen、fclose、fread、fwrite都是C标准库当中的函数,我们称之为库函数(libc)
- 系统调用接口:open、close、write、lseek(重新定位读/写文件偏移量)都属于系统提供的接口,我们称之为系统调用接口。
再来看一张图:

这里写图片描述

系统调用和库函数的关系,一目了然。所以,f#系列的函数,都是对系统调用的封装,方便二次开发。

原文链接:加载失败,请重新获取