栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

系统调用和库函数

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

系统调用和库函数

1、系统调用的本质

  所有操作的本质都是要下发命名到硬件,在Linux操作系统中提供了linux内核来驱动操作硬件、为了方便用户操作相关硬件功能,所以提供了一些函数接口,用于操作Linux内核,进而由内核来操作硬件。这些接口称之为系统调用。
  在Linux内核中,大多数的代码也是系统调用。在应用层调的一些函数接口,有些也是在函数接口内在调用内核中的系统调用函数。

文件io:称之为系统调用
标准io:称之为库函数

2、库函数

  库函数的本质是系统调用,系统调用函数只要执行一次,就需要对Linux内核访问一次,这样虽然效率较高,但是占用的资源比较大。
  库函数提供了一种方式,如果需要执行多次系统调用,在执行之前,会在内存中开辟一块空间,称之为缓冲区,缓冲区的目的就是将多次执行的系统调用的数据先保存起来,然后只需要执行一次系统调用即可,这样节省空间开销。库函数的目的就是为了减少系统调用的次数。
  不论是系统调用还是库函数,最终目的都是操作物理内存。

3、系统调用函数

文件io是系统调用,没有缓冲区,例如:open、read、write、lseek等。
标准io是库函数,有缓冲区,例如:fopen、fread、fwrite、ftell、fseek、fgets、fputs等。

标准io通过文件指针(FILE *)来操作文件
文件io通过文件描述符(int)对文件进行操作
当程序运行时或者创建了一个新的进程时,系统都会自动分配三个文件描述符

 标准io		   文件io
标准输入			stdin		0
标准输出			stdout		1
标准出错输出		stderr		2

下面对一些常用的系统调用函数简单介绍。

1、open()
#include 
#include 
#include 
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
功能:打开或者创建一个文件,返回一个文件描述符
参数:
    pathname:文件名,可以添加路径,默认为当前路径
    flags:访问权限标志位
        O_RDonLY 只读
        O_WRonLY 只写
        O_RDWR   可读可写
        O_CREAT  如果文件不存在则创建,如果会用此标志位,必须有第三个参数
        O_TRUNC  如果文件存在则清空
        O_APPEND 如果文件存在则追加
        O_EXCL   常与O_CREAT一起使用,表示如果文件存在则报错
   mode:文件创建的权限,一般传八进制数即可,例如0664   
返回值:
    成功:文件描述符
    失败:-1
2、close()
#include 
int close(int fd);
功能:关闭一个文件描述符,如果关闭文件描述符,
    则无法再通过这个文件描述符对文件进行操作
参数:
    fd:指定的文件描述符
返回值:
    成功:0
    失败:-1
3、perror()
#include 
void perror(const char *s);
功能:当函数调用失败后可以输出错误信息
参数:
    s:错误信息的提示信息
返回值:
    无
4、errno
errno变量在errno.h头文件中定义,
是一个全局变量,可以在任意位置使用,用于保存函数调用后的错误码

例如:

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

int main(int argc, const char *argv[])
{
	int fd;

	//使用open函数创建或者打开一个文件
	//if((fd = open("file.txt", O_RDONLY)) == -1)
	//if((fd = open("file.txt", O_RDonLY | O_CREAT | O_TRUNC, 0664)) == -1)
	//if((fd = open("file.txt", O_RDonLY | O_CREAT | O_APPEND, 0664)) == -1)
	if((fd = open("file.txt", O_RDonLY | O_CREAT | O_EXCL, 0664)) == -1)
	{
		//errno:用于函数执行失败后保存其失败的错误码,需要头文件,是一个全局变量
		//printf("errno = %dn", errno);

		//perror:当函数调用失败时,会输出错误信息
		perror("fail to open");
		return -1;
	}

	printf("fd = %dn", fd);

	//关闭文件描述符
	close(fd);
	return 0;
}
5、read()
#include 
ssize_t read(int fd, void *buf, size_t count);
功能:从文件中读取数据
参数:
    fd:指定的文件描述符
    buf:保存读取到的数据
    count:最大一次读取多少个字节
返回值:
    成功:实际读取的字节数
   失败:-1
   注意:如果读取到文件末尾,返回0

例如:

#include 
#include 
#include 
#include 
#include 

#define N 6

int main(int argc, char const *argv[])
{
    //从终端读取数据
    //从终端读取数据时,会把n也读取到
    //如果输入的数据大于设置读取的最大个数,会读取设置的字节数
#if 0
    char buf[N] = "";
    if(read(0, buf, sizeof(buf)) == -1)
    {
        perror("fail to read");
        return -1;
    }
    
    printf("buf = %s", buf);
#endif
    //从文件中读取数据
    int fd;
    if((fd = open("file.txt", O_RDONLY)) == -1)
    {
        perror("fail to open");
        return -1;
    }

    //注意:使用read函数读取文件内容是,要以返回值为标准表示实际读取的个数
    ssize_t bytes;
    char buf[40] = "";
    if((bytes = read(fd, buf, sizeof(buf))) == -1)
    {
        perror("fail to read");
        return -1;
    }

    printf("buf = %sn", buf);
    printf("bytes = %ldn", bytes);
    
    char buf1[40] = "";
    if((bytes = read(fd, buf1, sizeof(buf1))) == -1)
    {
        perror("fail to read");
        return -1;
    }

    printf("buf1 = %sn", buf1);
    printf("bytes = %ldn", bytes);

    return 0;
}
6、write()
#include 
ssize_t write(int fd, const void *buf, size_t count);
功能:向文件写入数据
参数:
    fd:指定的文件描述符
    buf:要写入的数据
    count:要写入的数据的长度
返回值:
    成功:实际写入的字节数
   失败:-1

例如:

#include 
#include 
#include 
#include 
#include 

int main(int argc, char const *argv[])
{
    //向终端写入数据
#if 0
    if(write(1, "hello worldn", 13) == -1)
    {
        perror("fail to write");
        return -1;
    }
#endif

    //向文件中写入数据
    int fd;
    if((fd = open("file.txt", O_WRonLY | O_CREAT | O_TRUNC, 0664)) == -1)
    {
        perror("fail to open");
        return -1;
    }

    if(write(fd, "hello world", 12) == -1)
    {
        perror("fail to write");
        return -1;
    }

    close(fd);

    return 0;
}
7、lseek()
#include 
#include 
off_t lseek(int fd, off_t offset, int whence);
功能:设置或者获取文件的偏移量
参数:
    fd:指定的文件描述符
    offset:偏移的位置,可正可负
    whence:相对位置
        SEEK_SET 文件起始位置
       SEEK_CUR 文件当前位置
       SEEK_END  文件末尾位置(最后一个字符的下一个位置)
返回值:
    成功:返回文件的当前偏移量
    失败:-1

例如

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

int main(int argc, char const *argv[])
{
    int fd;
    //if((fd = open(argv[1], O_RDWR | O_CREAT | O_TRUNC, 0664)) == -1)
    //注意:如果文件io中的open函数使用O_APPEND或者标准io的fopen函数使用a或者a+
    //     这样做无法修改写操作的偏移量,只能修改读操作的偏移量
    //     写操作只能在末尾处去写,而读操作可以指定偏移量
    if((fd = open(argv[1], O_RDWR | O_CREAT | O_APPEND, 0664)) == -1)
    {
        perror("fail to open");
        return -1;
    }

    char buf[128] = "hello world, nihao beijing, nihao chengdun";
    if(write(fd, buf, strlen(buf)) == -1)
    {
        perror("fail to write");
        return -1;
    }

    //不管是read还是write,执行完毕后都会修改文件的偏移量
    //获取当前文件的偏移量
    printf("offset = %ldn", lseek(fd, 0, SEEK_CUR));

    //修改文件的偏移量
    lseek(fd, 0, SEEK_SET);

    printf("offset = %ldn", lseek(fd, 0, SEEK_CUR));

    char text[128] = "";
    if(read(fd, text, sizeof(text)) == -1)
    {
        perror("fail to read");
        return -1;
    }

    printf("text = %sn", text);

    lseek(fd, 10, SEEK_SET);

    write(fd, "666666", 6);

    return 0;
}
8、remove()
#include 
int remove(const char *pathname);
功能:删除文件或者目录
参数:
    pathname:文件名或者目录名
返回值:
    成功:0
    失败:-1
4、库函数 1、fopen()
#include 
FILE * fopen(const char * path,const char * mode);
参数path字符串包含欲打开的文件路径及文件名,参数mode字符串则代表着流形态。
返回值:文件顺利打开后,指向该流的文件指针就会被返回。如果文件打开失败则返回NULL,并把错误代码存在errno 中
r  为 读操作 打开 文本文件. 流 被定位于 文件 的 开始. 
r+  为读写操作打开文本文件. 流 被定位于 文件 的 开始. 
w  为写操作创建文本文件, 或者 将 已经 存在的 文件长度 截断为 零. 流 被定位于 文件 的 开始. 
w+  为读写操作打开文件. 如果 文件 不存在, 就 创建 它, 否则 将它 截断. 流 被定位于 文件 的 开始. 
a  为追加操作 (在文件尾写) 打开 文件. 如果 文件 不存在, 就 创建 它. 流 被定位于 文件 的 末尾. 
a+  为追加操作 (在文件尾写) 打开 文件. 如果 文件 不存在, 就 创建 它. 读文件的初始位置 是 文件 的 开始, 但是 写文件 总是 被追加到 文件 的 末尾.

与open对比

2、fread()
#include 
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:从文件中读取数据
参数:
    ptr:保存读取的数据
    size:每次读取的字节数
    nmemb:一共读取的次数
    stream:文件指针
返回值:
    成功:实际读取的次数(对象数、块数)
    失败:0
    如果文件内容读取完毕,返回0

例如:将文件中信息读到结构体中

#include 

typedef struct{
    int a;
    int b;
    char c;
    char d[32];
}MSG;

int main(int argc, char const *argv[])
{
    //使用fread从文件中读取数据
    FILE *fp;
    if((fp = fopen("file.txt", "r")) == NULL)
    {
        perror("fail to fopen");
        return -1;
    }

    // char buf[32] = {0};
    // fread(buf, 2, 5, fp);
    // printf("buf = %sn", buf);
    
    // int num;
    // fread(&num, 4, 1, fp);
    // printf("num = %dn", num);

    // int b[4] = {0};
    // fread(b, 4, 4, fp);
    // printf("%d %d %d %dn", b[0], b[1], b[2], b[3]);
    
    MSG msg;
    fread(&msg, sizeof(msg), 1, fp);
    printf("%d - %d - %c - %sn", msg.a, msg.b, msg.c, msg.d);
    
    return 0;
}

3、fwrite()
#include 
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:向文件中写入数据
参数:
    ptr:要写入的数据
    size:一次写入的字节数
    nmemb:一共写入的次数
    stream:文件指针
返回值:
    成功:实际写入的次数
    失败:0

例如:

#include 

typedef struct{
    int a;
    int b;
    char c;
    char d[32];
}MSG;

int main(int argc, char const *argv[])
{
    //使用fwrite向文件写入数据
    FILE *fp;
    if((fp = fopen("file.txt", "w")) == NULL)
    {
        perror("fail to fopen");
        return -1;
    }

    //写入字符串
    //char buf[] = "1234567890";
    //fwrite(buf, 2, 5, fp);
    
    //写入整数
    //int a = 97868;
    //fwrite(&a, 4, 1, fp);

    //写入数组
    //int a[4] = {100, 200, 300, 400};
    //fwrite(a, 4, 4, fp);

    //写入结构体
    MSG msg = {666, 888, 'w', "zhangsan"};
    fwrite(&msg, sizeof(msg), 1, fp);

    return 0;
}
4、fgets()、fputs()

fgets()

#include 
char *fgets(char *s, int size, FILE *stream);
功能:从文件中读取内容
参数:
    s:保存读取到的内容
    size:每次读取的最大个数
    stream:文件指针
返回值:
    成功:读取的数据的首地址
   失败:NULL
   如果文件内容读取完毕,也返回NULL

fputs()

#include 
int fputs(const char *s, FILE *stream);
功能:向文件写入数据
参数:
    s:要写入的内容
    stream:文件指针
返回值:
    成功:写入文件内容的字节数
    失败:EOF
5、fseek()
#include 
int fseek(FILE *stream, long offset, int whence);
功能:设置文件位置指针的偏移量
参数:
    stream:文件指针
    offset:偏移量
        可正可负也可为0
    whence:相对位置
        SEEK_SET 文件起始位置
        SEEK_CUR 文件当前位置
       SEEK_END 文件末尾位置(最后一个字符后面一个位置)
返回值:
    成功:0
    失败:-1
6、rewind()
#include 
void rewind(FILE *stream);
功能:将文件位置定位到起始位置
参数:
    stream:文件指针
返回值:无

rewind(fp) <==> fseek(fp, 0, SEEK_SET);
7、ftell()
#include 
long ftell(FILE *stream);
功能:获取当前文件的偏移量
参数:
    stream:文件指针
返回值:
    获取当前文件的偏移量

例如:

#include 

int main(int argc, char const *argv[])
{
    //写操作的文件偏移量
#if 0
    FILE *fp;
    if((fp = fopen("file.txt", "w")) == NULL)
    {
        perror("fail to fopen");
        return -1;
    }

    fputs("abcdefghijklmnopq", fp);
    //使用ftell获取文件偏移量
    printf("offset = %ldn", ftell(fp));

    //使用fseek修改文件偏移量
    //rewind(fp);
    //fseek(fp, 0, SEEK_SET);
    
    fseek(fp, -5, SEEK_END);
    fputs("12345", fp);
#endif

#if 0
    FILE *fp;
    if((fp = fopen("file.txt", "r")) == NULL)
    {
        perror("fail to fopen");
        return -1;
    }

    char buf[32] = {0};
    fgets(buf, 6, fp);
    printf("buf = %sn", buf);

    printf("offset = %ldn", ftell(fp));
    fseek(fp, 3, SEEK_SET);
    printf("offset = %ldn", ftell(fp));

    fgets(buf, 6, fp);
    printf("buf = %sn", buf);
#endif

    FILE *fp;
    //如果fopen打开或者创建一个文件时使用的是的a或者a+权限
    //则写操作的偏移量无法改变,只能在文件的末尾位置
    //但是读操作没有任何影响
    if((fp = fopen("file.txt", "a+")) == NULL)
    {
        perror("fail to fopen");
        return -1;
    }

    // char buf[32] = {0};
    // fgets(buf, 6, fp);
    // printf("buf = %sn", buf);

    // printf("offset = %ldn", ftell(fp));
    // fseek(fp, 3, SEEK_SET);
    // printf("offset = %ldn", ftell(fp));

    // fgets(buf, 6, fp);
    // printf("buf = %sn", buf);

    fputs("888888888", fp);
    printf("offset = %ldn", ftell(fp));
    fseek(fp, 3, SEEK_SET);
    printf("offset = %ldn", ftell(fp));
    
    fputs("666666", fp);

    return 0;
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/751119.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号