嵌入式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个字节,并读取剩余的内容,将其打印到屏幕上。如果文件操作过程中出现错误,程序将显示错误信息并退出。运行结果如下:

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

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

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

前端解析文件流格式数据异常时并给提示

把后端返回的文件流格式转换成正常数据格式 断点调试返回值 network查看返回值 一、blob类型 let stringData:any await this.blobToString(res); blobToString(blob) { return new Promise((resolve, reject) > { const reader new FileReader(); reader.onloadend (…

通过U盘将第三方软件安装到各大品牌电视的方法

在本教程中&#xff0c;小武给大家整理了通过U盘的方式安装第三方软件到电视盒子上&#xff0c;可直接使用通用U盘的方式来进行安装。 如果您相应电视品牌按通用方式无法完成需求&#xff0c;下面为您也贴心整理了20款主流智能电视和电视盒子的U盘安装指南。这些步骤适用于小米…

Vxe UI vxe-form 实现折叠表单,当表单很多时实现自动收起与展开

Vxe UI vue vxe-form 实现折叠表单&#xff0c;当表单很多时实现自动收起与展开 代码 folding 用于将当前表单项设置为默认隐藏 collapse-node 设置折叠按钮&#xff0c;加上之后会自动在该表单项的右侧显示一个折叠按钮 <template><div><vxe-formtitle-colo…

c++ EECS280

Introduction Euchre (pronounced “YOO-kur”) is a card game popular in Michigan. The learning goals of this project include Abstract Data Types in C, Derived Classes, Inheritance, and Polymorphism. You’ll gain practice with C-style Object Oriented Progr…

操盘手专栏 | 0-1搞懂TikTok广告优化该怎么玩!

如果你正想要或计划投放TikTok广告来提高杠杆效益&#xff0c;是否有面临下面的难题&#xff1a; 难找到系统的TikTok投放知识&#xff1f; 不懂得如何制定广告计划&#xff1f; 投放效果怎样才算有效优化&#xff1f; ...... 为此&#xff0c;超店有数邀请到了拥有8年营销…

新媒体暴力起号必备因素!沈阳新媒体运营培训学校

1周涨粉10w&#xff1f;这对普通人来说可以说是天文数字&#xff0c;但只要掌握方式方法&#xff0c;普通人也能做到&#xff01; 面试经验丰富的人都深知&#xff0c;给面试官留下的第一印象相当重要&#xff0c;几乎决定了80%的面试机会。标题也是如此&#xff0c;在完成一篇…

华为面经整理

文章目录 实习第一面准备提问相关算法相关 第一面结果提问环节 总结 实习 第一面准备 提问相关 操作系统有哪些功能 进程管理&#xff1a; 进程调度、进程同步和通信、多任务处理 内存管理&#xff1a; 内存分配、虚拟内存技术、内存保护 文件系统管理&#xff1a; 文件存储…

达梦8 网络中断对系统的影响

测试环境&#xff1a;三节点实时主从 版本&#xff1a;--03134283938-20221019-172201-20018 测试1 系统没有启动确认监视器 关闭节点3网卡 登录节点1检查主库状态 显示向节点2发送归档成功&#xff0c;但无法收到节点3的消息&#xff0c;节点1挂起 日志报错如下&#xf…

Java和Web前端哪个有发展前景?

Java和Web前端都是当今技术行业里的热门岗位&#xff0c;岗位招聘需求量大&#xff0c;人才竞争度高&#xff0c;同学们掌握这两个岗位里其中任何一个的相关主流技术&#xff0c;都可以找到一份不错的职位。下面请允许笔者做一个简要的分析阐述&#xff1a; 一、Web前端 Web前…

算法题--华为od机试考试(围棋的气、用连续自然数之和来表达整数、亲子游戏)

目录 围棋的气 题目描述 输入描述 示例1 输入 输出 解析 答案 用连续自然数之和来表达整数 题目描述 输入描述 输出描述 示例1 输入 输出 说明 示例2 输入 输出 解析 答案 亲子游戏 题目描述 输入描述 输出描述 示例1 输入 输出 说明 示例2 输入…

plsql导入excel

1.建临时表&#xff1a;&#xff08;字段对应excel表头&#xff09; create table temp_old_table(atomname nvarchar2(4000), --原子名称koujingname nvarchar2(4000) --供应商名称);2.Plsql–>工具&#xff08;tool&#xff09;–>ODBC导入器&#xff08;ODBC Impo…

使用AutoGen框架进行多智能体协作:AI Agentic Design Patterns with AutoGen

AI Agentic Design Patterns with AutoGen 本文是学习https://www.deeplearning.ai/short-courses/ai-agentic-design-patterns-with-autogen/ 这门课的学习笔记。 What you’ll learn in this course In AI Agentic Design Patterns with AutoGen you’ll learn how to buil…

【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 持续时间断…

【人工智能】第三部分:ChatGPT的应用场景和挑战

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 目录 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌…

vue3+ts 拖拽容器边缘,改变容器宽度和高度

例如&#xff1a;我们的代码编辑器 终端与代码区&#xff0c;可以纵向拖拽&#xff0c;改变两个容器高度 目录与代码区可以横向拖拽&#xff0c;改变两个容器宽度 本文使用vue3tstailwindcss&#xff0c;把横向纵向整合在一起写了&#xff0c;也可以分开使用 utils目录下新建…

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

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

语音深度鉴伪识别项目实战:基于深度学习的语音深度鉴伪识别算法模型(二)音频数据预处理及去噪算法+Python源码应用

前言 深度学习技术在当今技术市场上面尚有余力和开发空间的&#xff0c;主流落地领域主要有&#xff1a;视觉&#xff0c;听觉&#xff0c;AIGC这三大板块。 目前视觉板块的框架和主流技术在我上一篇基于Yolov7-LPRNet的动态车牌目标识别算法模型已有较为详细的解说。与AIGC相…

Java使用OpenCV计算两张图片相似度

业务&#xff1a;找出两个表的重复的图片。 图片在表里存的是二进制值&#xff0c;存在大量由于一些特殊情况例如扫描有差异&#xff0c;导致图片存的二进制值不同&#xff0c;但图片其实是一样来的。 所以找出两个表重复相同的图片&#xff0c;不可能只是单纯的比较二进制值…

java版B/S架构UWB人员定位系统源码spring boot+vue技术架构uwb定位装置-工业级UWB室内定位系统源码

java版B/S架构UWB人员定位系统源码spring bootvue技术架构uwb定位装置-工业级UWB室内定位系统源码 本套系统运用UWB定位技术&#xff0c;开发的高精度人员定位系统&#xff0c;通过独特的射频处理&#xff0c;配合先进的位置算法&#xff0c;可以有效计算复杂环境下的人员与物…