嵌入式Linux系统编程 — 2.1 标准I/O库简介

目录

1 标准I/O库简介

1.1 标准I/O库简介

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

2 FILE 指针

3 标准I/O库的主要函数简介

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

4.1 标准输入、标准输出和标准错误概念

4.2 示例程序

5 打开文件fopen()

5.1 fopen()函数简介

5.2 新建文件的权限

5.3 示例程序

6 fread()和fwrite()读文件和写文件

6.1 fread()和fwrite()简介

6.2 示例程序

7 fseek()定位

7.1 fseek()函数简介

7.2 示例程序


1 标准I/O库简介

1.1 标准I/O库简介

Linux系统中的标准I/O库是C语言标准库的一个关键组成部分,它提供了一套丰富的函数接口,用于执行文件的输入输出操作。这些函数定义在<stdio.h>头文件中,包括打开和关闭文件、读取和写入数据、格式化输入输出等。由于标准I/O是C语言标准的一部分,因此使用标准I/O库编写的程序具有良好的可移植性。

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

  • 虽然标准 I/O 和文件 I/O 都是 C 语言函数,但是标准 I/O 是标准 C 库函数,而文件 I/O 则是 Linux系统调用;
  • 标准 I/O 是由文件 I/O 封装而来,标准 I/O 内部实际上是调用文件 I/O 来完成实际操作的;
  • 可移植性:标准 I/O 相比于文件 I/O 具有更好的可移植性,通常对于不同的操作系统,其内核向应用层提供的系统调用往往都是不同,譬如系统调用的定义、功能、参数列表、返回值等往往都是不一样的;而对于标准 I/O 来说,由于很多操作系统都实现了标准 I/O 库,标准 I/O 库在不同的操作系统之间其接口定义几乎是一样的,所以标准 I/O 在不同操作系统之间相比于文件 I/O 具有更好的可移植性。
  • 性能、效率: 标准 I/O 库在用户空间维护了自己的 stdio 缓冲区, 所以标准 I/O 是带有缓存的,而文件 I/O 在用户空间是不带有缓存的,所以在性能、效率上,标准 I/O 要优于文件 I/O。

2 FILE 指针

FILE 指针的作用相当于文件描述符,只不过 FILE 指针用于标准 I/O 库函数中、而文件描述符则用于文件I/O 系统调用中。

文件 I/O 函数都是围绕文件描述符进行的,当调用 open()函数打开一个文件时,即返回一个文件描述符 fd,然后该文件描述符就用于后续的 I/O 操作。而对于标准 I/O 库函数来说,它们的操作是围绕 FILE 指针进行的,当使用标准 I/O 库函数打开或创建一个文件时,会返回一个指向 FILE 类型对象的指针(FILE *) ,使用该 FILE 指针与被打开或创建的文件相关联,然后该 FILE 指针就用于后续的标准 I/O 操作。

FILE指针是C语言标准库中用于处理文件输入输出的一种数据类型。它指向FILE结构体的一个实例,这个结构体包含了执行文件操作所需的各种信息,如文件缓冲区、文件状态标志、错误标志以及指向文件当前位置的指针等。

3 标准I/O库的主要函数简介

(1) 打开文件

fopen(const char *filename, const char *mode)
  • filename:要打开的文件的名称。
  • mode:打开文件的模式,如"r"(只读),"w"(只写,会覆盖文件),"a"(追加),"r+"(读写)等。

(2) 关闭文件

fclose(FILE *stream)
  • stream:要关闭的文件的指针。

(3) 读取文件

fread(void *ptr, size_t size, size_t count, FILE *stream)
  • ptr:指向用于存储读取数据的缓冲区的指针。
  • size:每个数据项的大小(以字节为单位)。
  • count:要读取的数据项数量。
  • stream:指向包含要读取数据的文件的指针。

(4) 写入文件

fwrite(const void *ptr, size_t size, size_t count, FILE *stream)
  • ptr:指向要写入的数据的缓冲区的指针。
  • size:每个数据项的大小(以字节为单位)。
  • count:要写入的数据项数量。
  • stream:指向包含目标文件的指针。

(5) 从文件中读取一个字符

fgetc(FILE *stream)
  • stream:指向包含要读取字符的文件的指针。

(6) 从文件中读取一个字符

fputc(int c, FILE *stream)
  • c:要写入的字符(作为int类型传递)。
  • stream:指向包含目标文件的指针。

 (7) 从文件中读取一行字符串

fgets(char *str, int num, FILE *stream)
  • str:指向用于存储读取字符串的缓冲区的指针。
  • num:最大字符数,包括空字符'\0'。
  • stream:指向包含要读取数据的文件的指针。

 (8) 向文件写入一个字符串

fputs(const char *str, FILE *stream)
  • str:要写入的字符串。
  • stream:指向包含目标文件流的指针。

 (9) 输出数据

fprintf(FILE *stream, const char *format, ...)
  • stream:指向包含目标文件的指针。
  • format:格式字符串,定义了后续参数的输出格式。
  • ...:要输出的数据。

 (10) 检测文件是否到达文件末尾

feof(FILE *stream)
  • stream:指向要检查的文件的指针。

 (11) 检查文件流是否发生了错误

ferror(FILE *stream)
  • stream:指向要检查的文件的指针。

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

4.1 标准输入、标准输出和标准错误概念

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

在Linux系统中,标准输入(stdin)、标准输出(stdout)和标准错误(stderr)是进程与其环境之间通信的三种基本方式。它们是文件描述符,分别对应文件描述符0、1和2。下面是它们各自的功能:

标准输入(stdin)

  • 文件描述符:0
  • 功能:允许用户将输入数据发送给正在运行的程序。
  • 来源:通常是键盘输入,但也可以是重定向自文件、管道等。

标准输出(stdout)

  • 文件描述符:1
  • 功能:程序的输出结果默认发送到标准输出。
  • 去向:通常是终端或控制台(例如计算机所连接的显示器)。

标准错误(stderr)

  • 文件描述符:2
  • 功能:用于发送错误消息或诊断信息。
  • 去向:默认也是终端或控制台,但与标准输出分开,使得错误信息可以独立于正常输出被处理或重定向。

4.2 示例程序

下面的简单的示例程序会从标准输入读取一行文本,然后将这行文本通过标准输出打印出来,并同时将一个错误消息通过标准错误输出。

#include <stdio.h>
#include <string.h>int main() {char buffer[1024]; // 缓冲区,用于存储输入// 从标准输入读取一行文本printf("请输入一些文本:");fgets(buffer, sizeof(buffer), stdin); // 使用fgets从stdin读取// 将读取的文本通过标准输出打印printf("你输入的是:%s", buffer);// 检查输入的文本中是否包含空格if (strchr(buffer, ' ') != NULL) {// 如果包含空格,通过标准错误输出错误信息fprintf(stderr, "错误:输入的文本中包含空格。\n");}return 0;
}

在这个程序中:

  • stdinstdoutstderrstdio.h头文件中定义的宏,分别代表标准输入、标准输出和标准错误的文件指针。
  • fgets函数用于从stdin读取一行文本,直到遇到换行符或缓冲区满。它将文本存储在buffer数组中。
  • printf函数将读取的文本通过stdout打印到终端。
  • 使用strchr函数来检查输入的字符串中是否包含空格。如果strchr返回非空指针,表示输入中包含空格,程序通过stderr输出错误信息。

5 打开文件fopen()

5.1 fopen()函数简介

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

#include <stdio.h>FILE *fopen(const char *path, const char *mode);
  • path: 参数 path 指向文件路径,可以是绝对路径、也可以是相对路径。
  • mode: 参数 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
  • 返回值: 调用成功返回一个指向 FILE 类型对象的指针(FILE *),该指针与打开或创建的文件相关联,后续的标准 I/O 操作将围绕 FILE 指针进行。 如果失败则返回 NULL,并设置 errno 以指示错误原因。

5.2 新建文件的权限

fopen()只有两个参数 path 和 mode,不同于 open()系统调用,它并没有任何一个参数来指定新建文件的权限。 当参数 mode 取值为"w"、 "w+"、 "a"、 "a+"之一时,如果参数 path 指定的文件不存在,则会创建该文件。

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

S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH (0666)

5.3 示例程序

#include <stdio.h>int main() {FILE *file = fopen("example.txt", "w");if (file == NULL) {perror("Error opening file");return 1;}fprintf(file, "Hello, World!\n");fclose(file); // 记得关闭文件return 0;
}

示例代码中,以写入模式打开example.txt文件。如果文件打开失败,fopen()将返回NULL,通过perror()函数输出错误信息。成功打开文件后,使用fprintf()向文件写入内容,并最终使用fclose()关闭文件。运行的结果如下:

6 fread()和fwrite()读文件和写文件

6.1 fread()和fwrite()简介

库函数中使用 fread()用于读取文件数据,函数原型如下所示:

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

库函数中使用 fwrite()将数据写入到文件中,函数原型如下所示:

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

6.2 示例程序

下面代码演示了如何在C语言中使用标准I/O函数fopenfwriterewindfreadfclose来执行文件的基本读写操作。

#include <stdio.h>
#include <stdlib.h>int main() {const char *filename = "example.txt";char buffer[] = "Hello, World!";char readBuffer[sizeof(buffer)];// 打开文件用于写入和读取FILE *fp = fopen(filename, "w+");if (fp == NULL) {perror("Error opening file");return 1;}// 写入数据到文件if (fwrite(buffer, 1, sizeof(buffer), fp) != sizeof(buffer)) {fclose(fp);perror("Error writing to file");return 1;}// 移动文件指针到文件开头,准备读取rewind(fp);// 从文件读取数据if (fread(readBuffer, 1, sizeof(buffer), fp) != sizeof(buffer)) {fclose(fp);perror("Error reading from file");return 1;}// 确保字符串以空字符结尾readBuffer[sizeof(buffer) - 1] = '\0';// 打印读取的数据printf("Read from file: %s\n", readBuffer);// 关闭文件fclose(fp);return 0;
}

程序首先以读写模式打开一个名为"example.txt"的文件,然后向其中写入字符串"Hello, World!"。之后,程序将文件指针重置到文件开头,从文件中读取相同数量的数据到一个缓冲区,并确保字符串以空字符结尾,最后打印读取的字符串并关闭文件。程序还包括了基本的错误检查,以确保文件操作成功完成。程序运行结果如下:

 

7 fseek()定位

7.1 fseek()函数简介

库函数 fseek()的作用类似于系统调用 lseek(), 用于设置文件读写位置偏移量, lseek()用于文件 I/O,而库函数 fseek()则用于标准 I/O,其函数原型如下所示:

#include <stdio.h>int fseek(FILE *stream, long offset, int whence);
  • stream: FILE 指针。
  • offset: 与 lseek()函数的 offset 参数意义相同。
  • whence: 与 lseek()函数的 whence 参数意义相同。
  • 返回值: 成功返回 0;发生错误将返回-1,并且会设置 errno 以指示错误原因; 与 lseek()函数的返回值意义不同,这里要注意!

7.2 示例程序

如下程序如何使用fseek()来设置文件读写位置偏移量。

#include <stdio.h>
#include <stdlib.h>int main() {const char *filename = "input.txt";char buffer[1024];int i;// 打开文件用于写入FILE *file = fopen(filename, "w");if (file == NULL) {perror("Error opening file for writing");return 1;}// 提示用户输入文本printf("Enter your text (max 1024 characters): ");fgets(buffer, sizeof(buffer), stdin); // 从标准输入读取一行文本// 写入文本到文件fputs(buffer, file);// 关闭文件fclose(file);// 重新打开文件用于读取file = fopen(filename, "r");if (file == NULL) {perror("Error opening file for reading");return 1;}// 移动文件指针到文件开头fseek(file, 4, SEEK_SET);// 读取文件内容while (fgets(buffer, sizeof(buffer), file) != NULL) {printf("Read from file: %s", buffer);}// 关闭文件fclose(file);return 0;
}

代码创建了一个名为"input.txt"的文件,并提示用户输入一段文本。输入的文本被写入到文件中,然后程序重新打开文件跳过前4个字节,并读取剩余的内容,将其打印到屏幕上。如果文件操作过程中出现错误,程序将显示错误信息并退出。运行结果如下:

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/24214.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

时间序列新范式!多尺度+时间序列,刷爆多项SOTA

当我们面对复杂模式和多变周期的应用场景&#xff08;比如金融市场分析&#xff09;时&#xff0c;采用多尺度时间序列来做分析和预测是个更好的选择。 这是因为&#xff1a;传统时序方法通常只用固定时间窗口来提取信息&#xff0c;难以适应不同时间尺度上的模式变化。但多尺…

全程自动化操作 自动生成图文发布,矩阵批量软件系统 日产1-3万篇

一、简介 图文发布对于现代网站运营至关重要&#xff0c;然而手动创建和发布图文内容效率低下且易出错。全自动化图文生成发布流程可以解决这个问题。本文将详细说明如何以编程方式实现这一流程。 二、模块设计 该流程主要包含三个模块&#xff1a;图像生成&#xff0c;文本生成…

python-df的合并与Matplotlib绘图

1 数据连接 concat merge join &#xff08;append 作为了解&#xff09; append 竖直方向追加&#xff0c; 在最新的pandas版本中已经被删除掉了&#xff0c; 这里推荐使用concat 1.1 pd.concat 两张表&#xff0c; 通过行名、列名对齐进行连接 import pandas as pd df1 …

apifox 生成签名

目录 前言准备编写签名脚本签名说明捋清思路编码获取签名所需的参数生成签名将签名放到合适的位置完整代码 在apifox中配置脚本新增公共脚本引用公共脚本添加环境变量 参考 前言 略 准备 查看apifox提供的最佳实践文章&#xff1a;接口签名如何处理 编写签名脚本 签名说明…

Ant Design Pro

一&#xff1a;Ant Design pro是什么&#xff1a; Ant Design Pro 是基于 Ant Design 和 umi 的封装的一整套企业级中后台前端/设计解决方案&#xff0c;致力于在设计规范和基础组件的基础上&#xff0c;继续向上构建&#xff0c;提炼出典型模板/业务组件/配套设计资源&#x…

【JMeter接口测试工具】第二节.JMeter基本功能介绍(中)【入门篇】

文章目录 前言四、信息头管理器五、Jmeter参数化 5.1 用户自定义的变量 5.2 csv批量添加 5.3 用户参数 5.4 随机数函数 5.5 计数器函数 5.6 时间函数六、Jmeter断言 6.0 断言介绍 6.1 响应断言 6.2 大小断言 6.3 持续时间断…

【Python机器学习】主成分分析(PCA)

主成分分析&#xff08;PCA&#xff09;是一种旋转数据集的方法&#xff0c;旋转后的数特征在统计上不相关。在做完这种旋转之后&#xff0c;通常是根据新特征对解释数据的重要性来选择它的一个子集。 举例&#xff1a; import mglearn.plots import matplotlib.pyplot as pl…

python tqdm怎么安装

tqdm是一个显示循环的进度条的库。taqadum, تقدّم&#xff09;在阿拉伯语中的意思是进展。tqdm可以在长循环中添加一个进度提示信息&#xff0c;用户只需要封装任意的迭代器 tqdm(iterator)&#xff0c;是一个快速、扩展性强的进度条工具库。 tqdm库的安装 在CMD窗口下输…

利用梯度提升树分类法实现乳腺癌数据集分类

目录 1. 作者介绍2. 梯度提升树算法2.1 Boosting 算法2.2 Boosting Tree &#xff08;提升树&#xff09;2.3 梯度提升树&#xff08;Gradient Boosting Tree&#xff09; 3. 利用梯度提升树分类法实现乳腺癌数据集分类实验3.1 乳腺癌数据集介绍3.2 实验过程3.3 实验结果3.4 完…

【Microelectronic Systems】期末速通

PART1 嵌入式系统概述与玩转mbed 1 嵌入式系统&#xff0c;微控制器&#xff0c;与ARM 1.1什么是嵌入式系统&#xff1f; 微处理器不仅仅存在于通用计算机中&#xff0c;也可以安置在一些不需要计算的设备内部&#xff0c;比如洗衣机&#xff0c;摄像机。微处理器常常可以控制…

​【JS重点知识04】JS执行机制(重点面试题)

学前案例&#xff1a; console.log(111); setTimeout(function () {console.log(222); }, 1000) console.log(333); //输出结果&#xff1a;1111 333 222 console.log(111); setTimeout(function () {console.log(222); }, 0) console.log(333); //输出结果&#xff1a;111 33…

Django 里的表格内容做修改

当Django里表格内容需要做修改&#xff0c;可以这么操作。 先看效果图 修改后的表格 1. 先得在 asset_list.html 里修改。你们的html有可能跟我不一样 <table border"1px"><thead><tr><th>ID</th><th>标题</th><th…

AVL树【C++实现】

文章目录 AVL树的概念AVL树节点的定义AVL树的插入AVL树的旋转新节点插入较高右子树的右侧---右右&#xff1a;左单旋新节点插入较高左子树的左侧---左左&#xff1a;右单旋新节点插入较高左子树的右侧---左右&#xff1a;先左单旋再右单旋新节点插入较高右子树的左侧---右左&am…

【C++课程学习】:C++入门(函数重载)

&#x1f381;个人主页&#xff1a;我们的五年 &#x1f50d;系列专栏&#xff1a;C课程学习 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 目录 &#x1f308;函数重载&#xff1a; &#x1f349;1.参数个数不同&#xff1a; &#x1f349;2.参数…

ceph对象储存的使用

radosgw-admin user create --uid“user1” --display-name“user1” #创建用户 sudo apt install s3cmd cephadminceph-mgr01:~/ceph-cluster/s3$ s3cmd --configure Enter new values or accept defaults in brackets with Enter. Refer to user manual for detailed desc…

Visual C++ Redistributable下载

安装程序的时候提示丢失mfc140u.dll 如下图,查了资料说可以下载Visual C Redistributable来进行处理 下载Visual C Redistributable 1.打开网站 https://www.microsoft.com/zh-cn/download/details.aspx?id48145&751be11f-ede8-5a0c-058c-2ee190a24fa6True) 2.点击下载 …

Java面试题:Redis持久化问题

Redis持久化问题 RDB (Redis Database Backup File) Redis数据快照 将内存中的所有数据都记录到磁盘中做快照 当Redis实例故障重启时,从磁盘读取快照文件恢复数据 使用 save/bgsave命令进行手动快照 save使用主进程执行RDB,对所有命令都进行阻塞 bgsave使用子进程执行R…

创新案例 | AI数据驱动下的全域数字化转型的五大关键洞见

近年来通过全域数字化转型在竞争激烈的市场中脱颖而出。传统零食行业面临市场竞争加剧和消费者需求多样化的挑战&#xff0c;如何利用数据驱动和AI技术&#xff0c;能更好地实现会员运营效率和用户满意度的显著提升呢&#xff1f;本文将探讨全域数字化转型的五大关键洞见&#…

【C++】STL中List的基本功能的模拟实现

前言&#xff1a;在前面学习了STL中list的使用方法&#xff0c;现在我们就进一步的讲解List的一些基本功能的模拟实现&#xff0c;这一讲博主认为是最近比较难的一个地方&#xff0c;各位一起加油。 &#x1f496; 博主CSDN主页:卫卫卫的个人主页 &#x1f49e; &#x1f449; …

Excel 交叉表的格转成列,行转成格

Excel里交叉表的左表头是卡车号&#xff0c;上表头是工作&#xff0c;交叉格是工作编号。 ABCD1Truck NumberJob1Job2Job3271592859285928372395859282971473297159282971 要求&#xff1a;将交叉格转为列&#xff0c;左表头转为格。 ABC1297139585928272727137371473715726…