P5 Linux 标准C库函数

2023-12-13 04:02:41

目录

前言

01 标准输入、标准输出和标准错误

02 打开文件 fopen()

03 新建文件的权限

04 fclose()关闭文件

05 读文件和写文件

06 库函数 fseek 定位

6.1 lseek的使用

07 ftell()函数


前言

? ? ? ? ? ? ? ? ? ? ? ? ? ??

🎬 个人主页:@ChenPi

🐻推荐专栏1: 《C++_@ChenPi的博客-CSDN博客》????

🔥 推荐专栏2: 《Linux C应用编程(概念类)_@ChenPi的博客-CSDN博客》???

🛸推荐专栏3: ??????《 链表_@ChenPi的博客-CSDN博客 》 ???
🌺本篇简介 ?:? 上一章我们学了系统调用,open,read,write,lseek等等,这章我们学习一下C库函数的open,read,write函数

在Linux环境下,个人平时还是使用系统调用多一些,但相对于说可移值性来说,还是C库函数好,

而且相关的API还会多些

01 标准输入、标准输出和标准错误

  1. 标准输入设备指的就是计 算机系统的标准的输入设备,通常指的是计算机所连接的键盘;
  2. 标准输出设备指的是计算机系统中用于 输出标准信息的设备,通常指的是计算机所连接的显示器
  3. 标准错误设备则指的是计算机系统中用于显示 错误信息的设备,通常也指的是显示器设备。

每个进程启动之后都会默认打开标准输入、标准输出以及标准错误,得到三个文件描述符

STDIN_FILENO? ? 0 代表标准输入
STDOUT_FILENO? ?1 代表标准输出
STDERR_FILENO? ?2 代表标准错误

分别代表 0、1、2,这些宏定义在 unistd.h 头文件中:

/* Standard file descriptors. */?
#define STDIN_FILENO 0 /* Standard input. */?
#define STDOUT_FILENO1 /* Standard output. */?
#define STDERR_FILENO 2 /* Standard error output. */?


0、1、2 这三个是文件描述符,只能用于文件 I/O(read()、write()等),那么在标准 I/O 中,自然是无 法使用文件描述符来对文件进行 I/O 操作的,它们需要围绕 FILE 类型指针来进行,在 stdio.h 头文件中有相 应的定义,如下:

/* Standard streams. */?
extern struct _IO_FILE *stdin; /* Standard input stream. */?
extern struct _IO_FILE *stdout; /* Standard output stream. */?
extern struct _IO_FILE *stderr; /* Standard error output stream. */?
/* C89/C99 say they're macros. Make them happy. */?
#define stdin stdin?
#define stdout stdout?
#define stderr stderr?

Tips:struct _IO_FILE 结构体就是 FILE 结构体,使用了 typedef 进行了重命名。

所以,在标准 I/O 中,可以使用 stdin、stdout、stderr 来表示标准输入、标准输出和标准错误。

02 打开文件 fopen()

在 0 所介绍的文件 I/O 中,使用 open()系统调用打开或创建文件

而在标准 I/O 中,我们将使用库函数fopen()打开或创建文件,fopen()函数原型如下所示:

#include <stdio.h>?
?
FILE *fopen(const char *path, const char *mode);?

函数参数和返回值含义如下:

  1. path:参数 path 指向文件路径,可以是绝对路径、也可以是相对路径。
  2. mode:参数 mode 指定了对该文件的读写权限,是一个字符串,稍后介绍。
  3. 返回值:调用成功返回一个指向 FILE 类型对象的指针(FILE *),该指针与打开或创建的文件相关联, 后续的标准 I/O 操作将围绕 FILE 指针进行。如果失败则返回 NULL,并设置 errno 以指示错误原因

参数 mode 字符串类型,可取值为如下值之一:?

mode参数取值

  • r 以只读方式打开文件。
  • r+ 以可读、可写方式打开文件。
  • w 以只写方式打开文件,如果参数 path 指定的文件 存在,将文件长度截断为 0;如果指定文件不存在 则创建该文件。
  • w+ 以可读、可写方式打开文件,如果参数 path 指定 的文件存在,将文件长度截断为 0;如果指定文件 不存在则创建该文件。
  • a 以只写方式打开文件,打开以进行追加内容(在 文件末尾写入),如果文件不存在则创建该文 件。
  • a +以可读、可写方式打开文件,以追加方式写入 (在文件末尾写入),如果文件不存在则创建该 文件。


03 新建文件的权限


由 fopen()函数原型可知,fopen()只有两个参数 path 和 mode,

不同于 open()系统调用,它并没有任何一 个参数来指定新建文件的权限。

当参数 mode 取值为"w"、"w+"、"a"、"a+"之一时,如果参数 path 指定的文 件不存在

则会创建该文件,

那么新的文件的权限是如何确定的呢?

虽然调用 fopen()函数新建文件时无法手动指定文件的权限,但却有一个默认值:

S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH (0666)
使用示例

  1. 使用只读方式打开文件: fopen(path, "r");
  2. 使用可读、可写方式打开文件: fopen(path, "r+");
  3. 使用只写方式打开文件,并将文件长度截断为 0,如果文件不存在则创建该文件:fopen(path, "w");


04 fclose()关闭文件

调用 fclose()库函数可以关闭一个由 fopen()打开的文件,其函数原型如下所示:

#include <stdio.h>?
?
int fclose(FILE *stream);?


参数 stream 为 FILE 类型指针,调用成功返回 0;失败将返回 EOF(也就是-1),并且会设置 errno 来 指示错误原因。

05 读文件和写文件

?fread()和 fwrite()库函数

对文件进行读、写操 作了,函数原型如下所示:

#include <stdio.h>?
?
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);?
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);?

库函数 fread()
用于读取文件数据,其参数和返回值含义如下:

  1. ptr:fread()将读取到的数据存放在参数 ptr 指向的缓冲区中;
  2. size:fread()从文件读取 nmemb 个数据项,每一个数据项的大小为 size 个字节,所以总共读取的数据大 小为 nmemb * size 个字节。
  3. nmemb:参数 nmemb 指定了读取数据项的个数。
  4. stream:FILE 指针。
  5. 返回值:调用成功时返回读取到的数据项的数目(数据项数目并不等于实际读取的字节数,除非参数size 等于 1);

库函数 fwrite()
用于将数据写入到文件中,其参数和返回值含义如下:?

  1. ptr:将参数 ptr 指向的缓冲区中的数据写入到文件中。
  2. size:参数 size 指定了每个数据项的字节大小,与 fread()函数的 size 参数意义相同。
  3. nmemb:参数 nmemb 指定了写入的数据项个数,与 fread()函数的 nmemb 参数意义相同。
  4. stream:FILE 指针。
  5. 返回值:调用成功时返回写入的数据项的数目(数据项数目并不等于实际写入的字节数,除非参数 size等于 1);如果发生错误,则 fwrite()返回的值将小于参数 nmemb(或者等于 0)。

由此可知,库函数 fread()、fwrite()中指定读取或写入数据大小的方式与系统调用 read()、write()不同, 前者通过 nmemb(数据项个数)*size(每个数据项的大小)的方式来指定数据大小,而后者则直接通过一 个 size 参数指定数据大小。?

06 库函数 fseek 定位

库函数 fseek()则用于标准 I/O,其函数原型如下所示:

#include <stdio.h>?
?
int fseek(FILE *stream, long offset, int whence);?

函数参数和返回值含义如下: stream:FILE 指针。

  1. offset:与 lseek()函数的 offset 参数意义相同。
  2. whence:与 lseek()函数的 whence 参数意义相同。
  3. 返回值:成功返回 0;发生错误将返回-1,并且会设置 errno 以指示错误原因;与 lseek()函数的返回值 意义不同,这里要注意!

调用库函数 fread()、fwrite()读写文件时,文件的读写位置偏移量会自动递增,使用 fseek()可手动设置 文件当前的读写位置偏移量。?

6.1 lseek的使用

  1. 譬如将文件的读写位置移动到文件开头处: fseek(file, 0, SEEK_SET);
  2. 将文件的读写位置移动到文件末尾: fseek(file, 0, SEEK_END);
  3. 将文件的读写位置移动到 100 个字节偏移量处: fseek(file, 100, SEEK_SET);
fread,fwrite,fseek综合小案例?
#include <stdio.h>?
#include <stdlib.h>?
?
?
int main(void)?
?
{?
?FILE *fp = NULL;?
?char rd_buf[100] = {0};?
?char wr_buf[] = "hello world";?
?int ret;?
?
?/* 打开文件 */?
?if (NULL == (fp = fopen("./test_file", "w+"))) {?
?perror("fopen error");?
?exit(-1);?
?}?
?printf("文件打开成功!\n");?
?
?/* 写文件 */?
?if (sizeof(wr_buf) >?
?fwrite(wr_buf, 1, sizeof(wr_buf), fp)) {?
?
?printf("fwrite error\n");?
?fclose(fp);?
?exit(-1);?
?}?
?printf("数据写入成功!\n");?
?
?/* 将读写位置移动到文件头部 */?
?if (0 > fseek(fp, 0, SEEK_SET)) {?
?perror("fseek error");?
?fclose(fp);?
?exit(-1);?
?}?
?
?/* 读文件 */?
?if (sizeof(wr_buf) >?
?(ret = fread(rd_buf, 1, sizeof(wr_buf), fp))) {?
?printf("fread error\n");?
?fclose(fp);?
?exit(-1);?
?}?
?
?printf("成功读取%d 个字节数据: %s\n", ret, rd_buf);?
?
?/* 关闭文件 */?
?fclose(fp);?
?exit(0);?
?
}

07 ftell()函数

库函数 ftell()可用于获取文件当前的读写位置偏移量,其函数原型如下所示:

#include <stdio.h>?
?
long ftell(FILE *stream);?


参数 stream 指向对应的文件,函数调用成功将返回当前读写位置偏移量;调用失败将返回-1,并会设置errno 以指示错误原因。

文章来源:https://blog.csdn.net/weixin_73901182/article/details/134816208
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。