linux学习:标准IO

目录

接口

打开文件

关闭文件

读写

每次一个字符的读写标准 IO 函数接口

每次一行的读写标准 IO 函数接口

每次读写若干数据块的标准 IO 函数接口

获取或设置文件当前位置偏移量

标准格式化 IO 函数


系统 IO 的最大特点一个是更具通用性,不管是普通文件、管道文件、设备节点文件、 套接字文件等等都可以使用,另一个是他的简约性,对文件内数据的读写在任何情况下都是 不带任何格式的,而且数据的读写也都没有经过任何缓冲处理,这样做的理由是尽量精简内 核 API,而更加丰富的功能应该交给第三方库去进一步完善

标准 C 库是最常用的第三方库,而标准 IO 就是标准 C 库中的一部分接口,这一部分 接口实际上是系统 IO 的封装,他提供了更加丰富的读写方式,比如可以按格式读写、按 ASCII 码字符读写、按二进制读写、按行读写、按数据块读写等等,还可以提供数据读写 缓冲功能,极大提高程序读写效率

接口

打开文件

返回的文件指针是一种指向结构体 FILE{}的指针,该结构体在标准 IO 中被定义

typedef struct _IO_FILE FILE; // 定义 FILE 等价于 _IO_FILEstruct _IO_FILE {int _flags; /* High-order word is _IO_MAGIC; rest is flags. */#define _IO_file_flags _flags// The following pointers correspond to the C++ streambuf protocol. // Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. 251 char*                 _IO_read_ptr;char* _IO_read_end;char* _IO_read_base;char* _IO_write_base;char* _IO_write_ptr;char* _IO_write_end;char* _IO_buf_base;char* _IO_buf_end;/* The following fields are used to support backing up and undo. */char *_IO_save_base;char *_IO_backup_base;char *_IO_save_end;struct _IO_marker *_markers;struct _IO_FILE *_chain;int _fileno; // 文件描述符#if 0int _blksize;#elseint _flags2;#endif_IO_off_t _old_offset;#define __HAVE_COLUMN /* temporary *//* 1+column number of pbase(); 0 is unknown. */unsigned short _cur_column;signed char _vtable_offset;char _shortbuf[1];/* char* _save_gptr; char* _save_egptr; */_IO_lock_t *_lock;#ifdef _IO_USE_OLD_IO_FILE
};

数据将会先存储在一个标准 IO 缓冲区中,而后在一定条件下才被一并 flush(冲洗,或称刷新)至内核缓冲区,而不是像 系统 IO那样,数据直接被flush至内核

标准 IO 函数 fopen( )实质上是系统 IO 函数 open( )的封装,他们是一一对 应的,每一次 fopen( )都会导致系统分配一个 file{ }结构体和一个 FILE{}来保存维护该 文件的读写信息,每一次的打开和操作都可以不一样,是相对独立的,因此可以在多线程或 者多进程中多次打开同一个文件,再利用文件空洞技术进行多点读写

关闭文件

该函数用于释放由 fopen( )申请的系统资源,包括释放标准 IO 缓冲区内存,因此 fclose( )不能对一个文件重复关闭

读写

每次一个字符的读写标准 IO 函数接口

  • fgetc( )、getc( )和 getchar( )返回值是 int,而不是 char,原因是因为他们在出 错或者读到文件末尾的时候需要返回一个值为 -1 的 EOF 标记,而 char 型数据有可能因 为系统的差异而无法表示负整数。
  • 当 fgec( )、getc( )和 getchar( )返回 EOF 时,有可能是发生了错误,也有可能 是读到了文件末尾

  • getchar( )缺省从标准输入设备读取一个字符。
  • putchar( )缺省从标准输出设备输出一个字符。
  • fgetc( )和 fputc( )是函数,getc( )和 putc( )是宏定义。
  • 两组输入输出函数一般成对地使用,fgetc( )和 fputc( ),getc( )和 putc( ), getchar( )和 putchar( ).

普通文件的拷贝操作

1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdbool.h>
4 #include <unistd.h>
5 #include <string.h>
6 #include <strings.h>
7 #include <errno.h>
8
9 #include <sys/stat.h>
10 #include <sys/types.h>
11 #include <fcntl.h>
12
13 int main(int argc, char **argv)
14 {
15     if(argc != 3)
16     {
17         printf("Usage: %s <src> <dst>\n", argv[0]);
18         exit(1);
19     }
20
21     // 分别以只读和只写模式打开源文件和目标文件
22     FILE *fp_src = fopen(argv[1], "r");
23     FILE *fp_dst = fopen(argv[2], "w");
24
25     // 如果返回 NULL 则程序出错退出
26     if(fp_src == NULL || fp_dst == NULL)
27     {
28         perror("fopen()");
29         exit(1);
30     }
31
32     int c, total = 0;
33     while(1)
34     {
35         c = fgetc(fp_src); // 从源文件读取一个字符存储在变量 c 中
36
37         if(c == EOF && feof(fp_src)) // 已达文件末尾
38         {
39             printf("copy completed, " 40 "%d bytes have been copied.\n", total);
41             break;
42         }
43         else if(ferror(fp_src)) // 遇到错误
44         {
45             perror("fgetc()");
46             break;
47         }
48
49         fputc(c, fp_dst); // 将变量 c 中的字符写入目标文件中
50         total++; // 累计拷贝字符个数
51     }
52
53     // 正常关闭文件指针,释放系统资源
54     fclose(fp_src);
55     fclose(fp_dst);
56
57     return 0;
58 }

每次一行的读写标准 IO 函数接口

  • fgets( )跟 fgetc( )一样,当其返回 NULL 时并不能确定究竟是达到文件末尾还是 碰到错误,需要用 feof( )/ferror( )来进一步判断。
  • fgets( )每次读取至多不超过 size 个字节的一行,所谓“一行”即数据至多包含一 个换行符’\n’。
  • gets( )是一个已经过时的接口,因为他没有指定自定义缓冲区 s 的大小,这样很容 易造成缓冲区溢出,导致程序段访问错误。
  • fgets( )和 fputs( ),gets( )和 puts( )一般成对使用,鉴于 gets( )的不安全性, 一般建议使用前者。

普通文件拷贝

1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdbool.h>
4 #include <unistd.h>
5 #include <string.h>
6 #include <strings.h>
7 #include <errno.h>
8
9 #include <sys/stat.h>
10 #include <sys/types.h>
11 #include <fcntl.h>
12
13 #define BUFSIZE 100
14
15 int main(int argc, char **argv)
16 {
17     if(argc != 3)
18     {
19         printf("Usage: %s <src> <dst>\n", argv[0])
20         exit(1);
21     }
22
23     // 分别以只读和只写模式打开源文件和目标文件
24     FILE *fp_src = fopen(argv[1], "r");
25     FILE *fp_dst = fopen(argv[2], "w");
26
27     // 如果返回 NULL 则程序出错退出
28     if(fp_src == NULL || fp_dst == NULL)
29     {
30         perror("fopen()");
31         exit(1);
32     }
33
34     char buf[BUFSIZE]; // 自定义缓冲区
35     int total = 0;
36     while(1)
37     {
38         bzero(buf, BUFSIZE);
39         if(fgets(buf, BUFSIZE, fp_src) == NULL) // 从源文件读数据
40         {
41             if(feof(fp_src)) // 已达文件末尾
42             {
43                 printf("copy completed, %d bytes" 
44                     " have been copied.\n", total);
45                 break;
46             }
47             else if(ferror(fp_src)) // 遇到错误
48             {
49                 perror("fgetc()");
50                 break;
51             }
52         }
53
54         fputs(buf, fp_dst); // 将自定义缓冲区中的数据写入目标文件
55         total += strlen(buf); // 累计拷贝的字节个数
56     }
57
58     // 正常关闭文件指针,释放系统资源
59     fclose(fp_src);
60     fclose(fp_dst);
61
62     return 0;
63 }

每次读写若干数据块的标准 IO 函数接口

这一组标准 IO 函数被称为“直接 IO 函数”或者“二进制 IO 函数”,因为他们对数 据的读写严格按照规定的数据块数和数据块的大小来处理,而不会对数据格式做任何处理, 而且当数据块中出现特殊字符,比如换行符’\n’、字符串结束标记’\0’等时不会受到影响

  • 如果 fread( )返回值小于 nmemb 时,则可能已达末尾,或者遇到错误,需要借助 于 feof( )/ferror( )来加以进一步判断。
  • 当发生上述第 1 种情况时,其返回值并不能真正反映其读取或者写入的数据块数, 而只是一个所谓的“截短值”,比如正常读取 5 个数据块,每个数据块 100 个字节,在执行成功的情况下返回值是 5,表示读到 5 个数据块总共 500 个字节,但是如果只读到 499 个数据块,那么返回值就变成 4,而如果读到 99 个字节,那么 fread( )会返回 0。因此当发生返回值小于 nmemb 时,需要仔细确定究竟读取了几个字节,而不能直接从返回值确定。

获取或设置文件当前位置偏移量

  • fseek( )的用法基本上跟系统 IO 的 lseek( )是一致的。
  • rewind(fp)相等于 fseek(fp, 0L,

标准格式化 IO 函数

格式化 IO 函数中最常用的莫过于 printf( )和 scanf( )了,但从上表中可以看到,他 们其实各自都有一些功能类似的兄弟函数可用

  • fprintf( )不仅可以像 printf( )一样向标准输出设备输出信息,也可以向由 stream 指定的任何有相应权限的文件写入数据。
  • sprintf()和 snprintf()都是向一块自定义缓冲区写入数据,不同的是后者第二个参 数提供了这块缓冲区的大小,避免缓冲区溢出,因此应尽量使用后者,放弃使用前者。
  • fscanf( )不仅可以像 scanf( )一样从标准输入设备读入信息,也可以从由 stream 指定的任何有相应权限的文件读入数据。
  • sscanf( )从一块由 s 指定的自定义缓冲区中读入数据。 
  • 最重要的一条:这些函数的读写都是带格式的

假设有一个文件存储了班级学生的姓名、性别、年龄和身高,需要将这个文件读入程序,再将之打印到屏幕 显示出来

Mike M 18 167.2
Lucy F 17 155.3
Jack M 22 171.0
Joe  M 19 175.1
Rose F 21 169.1
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdbool.h>
4 #include <unistd.h>
5 #include <string.h>
6 #include <strings.h>
7 #include <errno.h>
8
9 #include <sys/stat.h>
10 #include <sys/types.h>
11 #include <fcntl.h>
12
13 #define NAMELEN 20
14
15 struct student // 用来存放一个带有一定数据格式的学生节点
16 {
17     char name[NAMELEN];
18     char sex;
19     int age;
20     float stature;
21
22     struct student *next; // 链表
23 };
24
25 struct student *init_list(void) // 初始化一个空链表
26 {
27     struct student *head = malloc(sizeof(struct student));
28     head->next = NULL;
29
30     return head;
31 }
32
33 // 将新节点 new 添加到链表 head 中
34 void add_student(struct student *head, struct student *new)
35 {
36     struct student *tmp = head;
37
38     while(tmp->next != NULL)
39     tmp = tmp->next;
40
41     tmp->next = new;
42 }
43
44 // 显示链表中的所有节点
45 void show_student(struct student *head)
46 {
47     struct student *tmp = head->next;
48
49     while(tmp != NULL)
50     {
51         fprintf(stdout, "%-5s %c %d %.1f\n", 52 tmp->name, tmp->sex, tmp->age, tmp->stature);
53
54         tmp = tmp->next;
55     }
56 }
57
58 int main(int argc, char **argv)
59 {
60     FILE *fp = fopen("format_data", "r");
61
62     // 创建一个用来保存学生节点的空链表
63     struct student *head = init_list();
64
65     int count = 0;
66     while(1)
67     {
68         struct student *new = malloc(sizeof(struct student));
69
70         // 从文件 fp 中按照格式读取数据,并将之填充到 new 中
71         if(fscanf(fp, "%s %c %d %f", 
72             new->name, &(new->sex), 
73             &(new->age), &(new->stature)) == EOF)
74         {
75             break;
76         }
77
78         // 将新节点 new 加入到链表 head 中
79         add_student(head, new);
80         count++;
81     }
82
83     printf("%d students have been added.\n", count);
84     show_student(head); // 打印所有的节点
85
86     fclose(fp); // 关闭文件指针,释放系统资源
87
88     return 0;
89 }

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

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

相关文章

mac上如何安装python3

mac上如何安装python3&#xff1f; 安装homebrew 在终端执行命令 /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" 执行完成后&#xff0c;homebrew和pip等工具就自动安装好了。 接下来安装python3.在终端…

AndroidAutomotive模块介绍(三)CarService服务

前言 上一篇文档总结 Android Automotive 框架的 APP 和 API 部分内容&#xff0c;本篇文档将会继续根据 Android Automotive 框架结构&#xff0c;总结 Framework 层 CarService 服务的内容。 本文档对 Android Automotive Framework 层服务将会按照如下顺序展开描述&#x…

分布式强化学习

标题 易混淆概念联邦学习与强化学习1&#xff09;联邦学习应用于强化学习2&#xff09;强化学习应用于联邦学习 时空图卷积网络&#xff08;ST-GCN&#xff09;基本概念结合训练 易混淆概念 DistributionalRL是分布RL&#xff0c;不是分布式RL。分布RL是把Q值从一个期望构建成…

MySQL——创建和插入

一、插入数据 INSERT 使用建议; 在任何情况下建议列出列名&#xff0c;在 VALUES 中插入值时&#xff0c;注意值和列的意义对应关系 values 指定的值顺序非常重要&#xff0c;决定了值是否被保存到正确的列中 在指定了列名的情况下&#xff0c;你可以仅对需要插入的列给到…

【链表】1移除链表元素

这里写自定义目录标题 一、题目二、先考虑头结点&#xff0c;再考虑非头结点三、虚拟头结点解决 一、题目 给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 二、先考虑头结点&#xff0c;…

Okhttp全链路监控

目标&#xff1a; 1&#xff09;.监控网络请求的各个阶段 2&#xff09;获取每一个阶段的耗时和性能&#xff0c;用于性能分析。包括dns解析&#xff0c;socket连接时间&#xff0c;tls连接时间&#xff0c;请求发送时间&#xff0c;服务器接口处理时间&#xff0c;应答传输时…

机器学习-09-图像处理02-PIL+numpy+OpenCV实践

总结 本系列是机器学习课程的系列课程&#xff0c;主要介绍机器学习中图像处理技术。 参考 【人工智能】PythonOpenCV图像处理&#xff08;一篇全&#xff09; 一文讲解方向梯度直方图&#xff08;hog&#xff09; 【杂谈】计算机视觉在人脸图像领域的十几个大的应用方向&…

线性代数

标量、向量、张量 标量占据的是零维空间向量占据的是一维数据&#xff0c;例如语音信号矩阵占据的是二维数组&#xff0c;例如灰度图像张量占据的是三维乃至更高维的数组&#xff0c;例如RGB图像和视频 内积(点乘)概述 内积(inner product) 计算的则是两个向量之间的关系 两…

gpt系列概述——从gpt1到chatgpt

GPT建模实战&#xff1a;GPT建模与预测实战-CSDN博客 OpenAI的GPT&#xff08;Generative Pre-trained Transformer&#xff09;系列模型是自然语言处理领域的重要里程碑。从2018年至2020年&#xff0c;该公司相继推出了GPT-1、GPT-2和GPT-3&#xff0c;这些模型在文本生…

kali工具----枚举工具

一、枚举工具 枚举是一类程序&#xff0c;它允许用户从一个网络中收集某一类的所有相关信息。本节将介绍DNS枚举和SNMP枚举技术。DNS枚举可以收集本地所有DNS服务和相关条目。DNS枚举可以帮助用户收集目标组织的关键信息&#xff0c;如用户名、计算机名和IP地址等&#xff0c;…

前端js基础知识(八股文大全)

一、js的数据类型 值类型(基本类型)&#xff1a;数字(Number)、字符串&#xff08;String&#xff09;、布尔(Boolean)、对空&#xff08;Null&#xff09;、未定义&#xff08;Undefined&#xff09;、Symbol,大数值类型(BigInt) 引用数据类型&#xff1a;对象(Object)、数组…

智能售货机:引领便捷生活

智能售货机&#xff1a;引领便捷生活 在这个科技迅速进步的时代&#xff0c;便捷已成为生活的必需。智能售货机作为技术与便利完美结合的产物&#xff0c;正逐渐改变我们的购物方式&#xff0c;为都市生活增添新的活力。 智能售货机的主要优势是它的极致便利性。不论是在地铁…

javaweb day29

事务 写法 事务的四大特性

AndroidAutomotive模块介绍(四)VehicleHal介绍

前言 前面的文章中&#xff0c;描述了 Android Automotive 的框架中应用、Framework 层服务等知识&#xff0c;本篇文章将会继续按照 Android Automotive 框架介绍 Vehicle Hal 层服务的内容。 上一篇&#xff1a;AndroidAutomotive模块介绍&#xff08;三&#xff09;CarSer…

如何选择适用于Mac的文件恢复软件?适用于 Mac 的最佳数据恢复软件清单

有人会说&#xff0c;我们的数字生活正变得几乎和我们的物理生活一样重要。我们在线工作&#xff0c;将记忆保存在数码照片库中&#xff0c;在信使中交流&#xff0c;并保留各种文档的数字扫描。 每个人都知道备份是必不可少的。建议每天至少同步一个数字备份&#xff08;例如…

物联网实战--驱动篇之(八)磁编码器(AS5600)

目录 一、AS5600磁编码简介 二、AS5600使用 一、AS5600磁编码简介 AS5600是一款性价比极高的磁编码传感器&#xff0c;一般用于电机转动位置的记录&#xff0c;一般采用IIC通讯&#xff0c;也可以用模拟信号获取转动角度&#xff0c;具体资料在这里。AS5600-ASOM_&#xff08…

Argus DBM 一款开源的数据库监控工具,无需部署Agent

开箱即用 无需部署Agent&#xff0c;开箱即用。我们使用JDBC直连您的数据库&#xff0c;输入IP端口账户密码即可。 全平台支持 Argus目前支持对Mysql, PostgreSQL, Oracle等数据库类型的监控&#xff0c;我们也会尽快适配其它数据库&#xff0c;致力于监控所有数据库。我们提…

c++命令行解析开源库cxxopts上手教程

文章目录 cxxopts快速入门1. cmake环境配置2. 定义解析的规则3. 使用例子 cxxopts 简介 cxxopts是一个轻量级的C命令行解析库&#xff0c;它提供了易于使用的API来定义和解析命令行选项。它支持多种类型的选项&#xff0c;并且允许用户自定义选项的处理逻辑。 项目地址&#x…

【网安播报】GitHub上的恶意Visual Studio 项目推送 Keyzetsu 恶意软件

1、GitHub 上的恶意 Visual Studio 项目推送 Keyzetsu 恶意软件 威胁行为者正在滥用 GitHub 自动化功能和恶意 Visual Studio 项目来推送“Keyzetsu”恶意软件的新变种并窃取加密货币付款。攻击者创建了GitHub 存储库&#xff0c;并使用各种方法来人为地提高其在平台上的受欢迎…

Android广播之监听应用程序安装与卸载

&#x1f604;作者简介&#xff1a;小曾同学.com,一个致力于测试开发的博主⛽️&#xff0c; 如果文章知识点有错误的地方&#xff0c;还请大家指正&#xff0c;让我们一起学习&#xff0c;一起进步。&#x1f60a; 座右铭&#xff1a;不想当开发的测试&#xff0c;不是一个好测…