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.mzph.cn/news/812171.shtml

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

相关文章

web笔记再整理

前四天笔记在此连接: web前端笔记表单练习题五彩导航栏练习题-CSDN博客https://blog.csdn.net/simply_happy/article/details/136917265?spm1001.2014.3001.5502 # 1.边框弧度​ div {​ width: 300px;​ height: 50px;​ background-color: aqua;​ …

【刷题】图论——最小生成树:Prim、Kruskal【模板】

假设有n个点m条边。 Prim适用于邻接矩阵存的稠密图&#xff0c;时间复杂度是 O ( n 2 ) O(n^2) O(n2)&#xff0c;可用堆优化成 O ( n l o g n ) O(nlogn) O(nlogn)。 Kruskal适用于稀疏图&#xff0c;n个点m条边&#xff0c;时间复杂度是 m l o g ( m ) mlog(m) mlog(m)。 Pr…

基于单片机的智能模拟路灯控制系统

摘 要: 随着电力资源的紧缺,以及光污染和雾霾天气的影响,更智能化的路灯设计对人们的日常生活意义重大。本文的智能路灯控制系统是基于单片机的控制器,通过介绍该系统相应的硬件设计和软件设计,实现定时开关和依具体情况是否需要来开关路灯和进行亮度调节,并且具有自检功能…

Springboot+Vue项目-基于Java+MySQL的房产销售系统(附源码+演示视频+LW)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;Java毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计 &…

谷歌现在被授权在云端托管机密数据

谷歌公共部门在周二为其美国政府客户实现了一个重要里程碑&#xff0c;宣布国防部授权其云平台托管秘密和绝密机密数据。 这项认证立即使谷歌的云产品与竞争对手亚马逊网络服务、 微软和甲骨文相比更具竞争力&#xff0c;因为它们在国防部和情报机构内争夺价值数十亿美元的业…

opencv 多线程读取和显示摄像头【python源码】

在Python中&#xff0c;使用OpenCV库实现多线程读取和显示摄像头通常涉及创建多个线程&#xff0c;每个线程负责从摄像头捕获视频帧并显示它们。但是&#xff0c;请注意&#xff0c;OpenCV本身并不直接支持多线程显示&#xff0c;因为cv2.imshow通常是在主线程中运行的。然而&a…

明明设置数字居中对齐,为什么excel的数字却不居中?

有时候在excel里&#xff0c;选中数据&#xff0c;设置对齐方式 左右居中&#xff0c;然而&#xff0c;数字却怎么都不居中&#xff0c;为什么呢&#xff1f; 1.按快捷键Ctrl1&#xff0c;打开单元格自定义格式对话框&#xff0c;看到是初始界面是在数字的会计专用&#xff0c;…

蓝桥杯python速成

总写C&#xff0c;脑子一热&#xff0c;报了个Python&#xff08;有一点想锤死自己&#xff09;&#xff0c;临时抱佛脚了 1.list的插入删除 append extend insert&#xff08;在索引位插入99&#xff09;---忘记用法别慌&#xff0c;用help查询 remove&#xff08;去掉第一个3…

【测试开发学习历程】python类的继承

目录 1 继承的概念 2 继承的写法 3 子类继承父类的属性和方法 4 子类新增父类没有的属性和方法 5 子类重写父类的属性和方法 6 super超类的使用 7 多继承 1 继承的概念 继承是类与类之间的一种关系&#xff0c;子类继承父类。通过继承可以使得子类能够拥有父类的属性和方…

scanf()返回转换成功的个数

一、概要 1、scanf()的读取与返回 scanf()&#xff0c;敲下回车进行一次读取&#xff0c;如果没有读到或没有读够&#xff0c;就继续等待输入 scanf()一次可以读取一个&#xff0c;也可以读取多个&#xff0c;多个之间用空格隔开 读取的数据按照%后面的字符格式进行转换&am…

【CSS面试题】Flex实现九宫格

考察知识&#xff1a; flex布局 水平垂直居中的实现 初始效果 代码关键&#xff1a;给父盒子添加以下属性 flex-wrap: wrap; /* 允许换行 */justify-content: space-around; /* 主轴对齐方式 */align-content: space-around; /* 多行在侧轴上的对齐方式 */<!DOCTYPE html&…

Java 自定義 List<T> 分頁工具

Java 自定義 List 分頁工具 PS: T可修改为对应的实体 rt com.google.common.collect.Lists;import java.util.Arrays; import java.util.Collections; import java.util.List;/*** ClassName: MyPageHelper* Descripution: List<T>分頁工具**/ public class MyPageHelp…

10BASE-T1S架构助力车载E/E领域,引领汽车产业迈向智能化新纪元!

汽车架构的发展 如今&#xff0c;汽车已不仅仅满足消费者的代步需求&#xff0c;而是向所谓的ACES&#xff08;Autonomous, Connected, Electrification, Shared Source&#xff09;方向发展&#xff0c;全自动驾驶和网联化将成为最终目标。由此带来的高算力和高数据吞吐量问题…

政安晨:【Keras机器学习实践要点】(二十八)—— 使用Reptile进行小样本学习

目录 介绍 定义超参数 准备数据 可视化数据集中的一些示例 建立模型 训练模型 可视化结果 政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: TensorFlow与Keras机器学习实战 希望政安晨的博客能够对您有所裨益&#xff0c;如有不足之处…

数据库练习

insert into employee(empno,ename,job,mgr,hiredate,sal,comm,deptno) values (1001,甘宁,文员,1013,2000-12-17,8000.00,NULL,20), (1002,黛绮丝,销售员,1006,2001-02-20,16000.00,3000.00,30), (1003,殷天正,销售员,1006,2001-02-22,12500.00,5000.00,30), (1004,刘备,经理,…

kimichat使用技巧:用语音对话聊天

kimichat之前是只能用文字聊天的&#xff0c;不过最近推出了语音新功能&#xff0c;也可以用语音畅快的对话聊天了。 这个功能目前支持手机app版本&#xff0c;所以首先要在手机上下载安装kimi智能助手。已经安装的&#xff0c;要点击检查更新&#xff0c;更新到最新的版本。 …

Ubuntu 20.04 设置开启 root 远程登录连接

Ubuntu默认不设置 root 帐户和密码 Ubuntu默认不设置 root 帐户和密码 Ubuntu默认不设置 root 帐户和密码 如有需要&#xff0c;可在设置中开启允许 root 用户登录。具体操作步骤如下&#xff1a; 操作步骤 1、首先使用普通用户登录 2、设置root密码 macw:~$ sudo passwd …

Llama2模型本地部署(Mac M1 16G)

环境准备 环境&#xff1a;Mac M1 16G、Conda Conda创建环境配置 使用Anaconda-Navigator创建python 3.8环境 切换到新建的conda环境&#xff1a; conda activate llama38 llama.cpp 找一个目录&#xff0c;下载llama.cpp git clone https://github.com/ggerganov/llama.…

读所罗门的密码笔记18_大宪章

1. 大宪章 1.1. 1215年会议开启了一个艰难的谈判过程&#xff0c;充满了紧张和对权力与道德权威的争夺 1.1.1. 这部宪章会赋予各方一系列的权力&#xff0c;对国王的自由裁量权进行制衡 1.2. 《大宪章》还需要300多年的时间和多次迭代&#xff0c;才能成为财产权、公平税收、…

STM32 DCMI 的带宽与性能介绍

1. 引言 随着市场对更高图像质量的需求不断增加&#xff0c;成像技术持续发展&#xff0c;各种新兴技术&#xff08;例如3D、计算、运动和红外线&#xff09;的不断涌现。如今的成像应用对高质量、易用性、能耗效率、高集成度、快速上市和成本效益提出了全面要求。为了满足这些…