Linux应用开发:标准IO库(上)

举报
JeckXu666 发表于 2022/01/14 23:20:40 2022/01/14
【摘要】 文章目录 Linux应用开发:标准IO库(上)一、标准IO库简介二、流和 FILE 对象三、标准输入、输出、错误四、标准 I/O 库函数操作文件4.1 打开关闭文件4.2 读文件4.3 写文件4....

Linux应用开发:标准IO库(上)

一、标准IO库简介

标准 I/O 库是标准 C 库中用于文件 I/O 操作(读、写文件等操作)相关的一系列库函数的集合,通常标准 I/O 库函数相关的函数定义都在 <stdio.h> 头文件中

标准 I/O 库函数 本质上就是构建于文件 I/O(open()、read()、write()、lseek()、close()等)这些系统调用之上,对这些系统调用进行了封装

标准 I/O 和文件 I/O 的区别:

  • 标准 I/O 是标准 C 库函数,而文件 I/O 则是 Linux 系统调用
  • 标准 I/O 内部实际上是调用文件 I/O 来完成实际操作的
  • 标准 I/O 相比于文件 I/O 具有更好的可移植性,系统调用对不不同版本系统可能不同,但标准 I/O 一般都是统一封装,更加规范,容易移植
  • 标准 I/O 库在用户空间维护了自己的 stdio 缓冲区,所以 标准 I/O 是带有缓存的,而 文件 I/O 在用户空间是不带有缓存的,所以在性能、效率上,标准 I/O 要优于文件 I/O

二、流和 FILE 对象

在系统调用中,所有文件 I/O 函数(open()、read()、write()、lseek()等)都是围绕文件描述符进行的,而对于标准 I/O 库函数来说,它们的操作是 围绕 FILE 指针进行的

在使用标准 I/O 库函数打开或创建一个文件时,会返回一个指向 FILE 类型对象的指针(FILE *),标准 I/O 的所有文件操作都是围绕这个指针进行

FILE 是一个结构体,包含了标准 I/O 库函数为管理文件所需要的所有信息,包括用于系统调用的文件描述符、指向文件缓冲区的指针、缓冲区的长度、当前缓冲区中的字节数以及出错标志等。FILE 数据结构定义在标准 I/O 库函数头文件 stdio.h 中

三、标准输入、输出、错误

  • 标准输入:

标准输入设备指的就是计算机系统的标准的输入设备,通常指的是计算机所连接的键盘

  • 标准输出:

标准输出设备指的是计算机系统中用于输出标准信息的设备,通常指的是计算机所连接的显示器

  • 标准错误:

标准错误设备则指的是计算机系统中用于显示错误信息的设备,通常也指的是显示器设备

用户通过标准输入设备与系统进行交互,进程将从标准输入(stdin)文件中得到输入数据,将正常输出数据(譬如程序中 printf 打印输出的字符串)输出到标准输出(stdout)文件,而将错误信息(譬如函数调用报错打印的信息)输出到标准错误(stderr)文件

所以标准输入、输出、错误都是围绕文件的操作,所以每个进程启动之后都会默认打开标准输入、标准输出以及标准错误,得到三个文件描述符,即 0、1、2,其中 0 代表标准输入、1 代表标准输出、2 代表标准错误

应用编程中 可以使用宏 STDIN_FILENO、STDOUT_FILENO 和 STDERR_FILENO 分别代表 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. */

  
 
  • 1
  • 2
  • 3
  • 4

以上的是文件描述符,在标准 I/O 中如果要对这三个文件进行操作,则要对 FILE 对象进行操作,在 unistd.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

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

struct _IO_FILE 结构体就是 FILE 结构体,只不过用 typedef 进行了重命名

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

四、标准 I/O 库函数操作文件

4.1 打开关闭文件

标准 I/O 中,使用库函数 fopen() 打开或创建文件,函数原型如下:

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

  
 
  • 1
  • 2

使时需要包含头文件 stdio.h

函数参数和返回值含义:

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

参数 mode 补充:

mode 说明 对应于 open() 系统调用函数的 flags 参数取值
r 以只读方式打开文件 O_RDONLY
r+ 以可读可写方式打开文件 O_RDWR
w 以只写方式打开文件,如果参数path指定的文件存在,将文件长度截断为0,如果指定文件不存在 则创建该文件 O_WRONLY |O_CREAT| O_TRUNC
w+ 以可读可写方式打开文件,如果参数path指定的文件存在,将文件长度截断为0;如果指定文件 不存在则创建该文件 O_RDWR|O_CREAT|O_TRUNC
a 以只写方式打开文件,打开以进行追加内容(在文件末尾写入),如果文件不存在则创建该文件 O_WRONLY | O_CREAT|O_APPEND
a+ 以可读可写方式打开文件,以追加方式写入 (在文件末尾写入),如果文件不存在则创建该文件 O_RDWR |O_CREAT|O_APPEND

打开的文件通过 fclose() 进行关闭,关闭函数原型如下:

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

  
 
  • 1
  • 2

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

4.2 读文件

使用 fread() 对文件进行读操作,函数原型如下:

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

  
 
  • 1
  • 2

参数和返回值含义:

参数 含义
ptr: fread() 将读取到的数据存放在参数 ptr 指向的缓冲区中
size: fread()从文件读取 nmemb 个数据项,每一个数据项的大小为 size 个字节,所以总共读取的数据大小为 nmemb * size 个字节
nmemb: 参数 nmemb 指定了读取 数据项的个数
stream: FILE 指针
返回值: 调用成功时返回读取到的数据项的数目(数据项数目并不等于实际读取的字节数,除非参数size 等于 1);如果发生错误或到达文件末尾,则 fread()返回的值将小于参数 nmemb,那么到底发生了错误还是到达了文件末尾,fread()不能区分文件结尾和错误,究竟是哪一种情况,此时可以使用 ferror()或 feof()函数来判断,具体参考 4.7 小节内容的介绍

4.3 写文件

fwrite() 库函数进行写操作,函数原型如下:

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

  
 
  • 1
  • 2

参数和返回值含义:

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

4.4 定位文件

  • 库函数 fseek() 用于设置文件读写位置偏移量,和 lseek() 功能相同,但 lseek() 用于文件 I/O,而库函数 fseek() 则用于标准 I/O,函数原型:
#include <stdio.h>
int fseek(FILE *stream, long offset, int whence);

  
 
  • 1
  • 2

函数参数和返回值含义

参数 含义
stream FILE 流指针
offset 与 lseek() 函数的 offset 参数意义相同,相对偏移位置的偏移值
whence 与 lseek()函数的 whence 参数意义相同,偏移位置
返回值 成功返回 0;发生错误将返回-1,并且会设置 errno 以指示错误原因;与 lseek()函数的返回值意义不同,这里要注意
  • 库函数 ftell() 可用于获取文件当前的读写位置偏移量,函数原型如下:
#include <stdio.h>
long ftell(FILE *stream);

  
 
  • 1
  • 2

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

文章来源: blog.csdn.net,作者:JeckXu666,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/qq_45396672/article/details/121662112

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。