linux学习:标准IO

目录

接口

打开文件

关闭文件

读写

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

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

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

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

标准格式化 IO 函数


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

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

接口

打开文件

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

typedef struct _IO_FILE FILE; // 定义 FILE 等价于 _IO_FILE

struct _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 0
        int _blksize;
    #else
        int _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 }

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

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

相关文章

障碍物识别技术赋能盲人独立出行:一场静默的科技革新

作为一名资深记者&#xff0c;我始终关注并报道那些科技如何助力特殊群体克服生活挑战的动人故事。近期&#xff0c;一款叫做蝙蝠避障的应用进入了我的视线&#xff0c;它搭载先进障碍物识别技术以其独特的优势&#xff0c;悄然为视障人士的独立出行带来了显著变革。 “障碍物识…

asm磁盘组无法写入问题-处理中

有个11204的rac环境&#xff0c;没应用补丁&#xff0c;5号突然报归档满&#xff0c;登录环境后发现奇怪&#xff0c;一个1T磁盘建成的DATA磁盘组使用了近800G&#xff0c;读写正常&#xff0c;一个1.5T磁盘建成的FRA磁盘组&#xff0c;目前还剩余729551M&#xff0c;无法写入归…

AutoCAD之DWF三维信息提取---linux编译篇

1. 权限 1.1 给文件添加执行权限 chmod x autogen.sh1.2.给当前文件下的所有文件改变为读写执行权限 chmod 777 * -R 2.环境安装 2.1安装automake 1.4.1 安装链接 安装中遇到的问题及解决 2.2安装autoconf 2.3 安装libtool 2.4 安装Cmake(CMake包含) cmake安装在cent…

STM32—DMA直接存储器访问详解

DMA——直接存储器访问 DMA&#xff1a;Data Memory Access, 直接存储器访问。 DMA和我们之前学过的串口、GPIO都是类似的&#xff0c;都是STM32中的一个外设。串口是用来发送通信数据的&#xff0c;而DMA则是用来把数据从一个地方搬到另一个地方&#xff0c;而且不占用CPU。…

windows本地运行dreamtalk踩坑总结

dreamtalk是一个语音图片转视频的一个工具&#xff0c;就是给一段语音加一个头像图片&#xff0c;然后生成一段头像跟语音对口型的视频&#xff0c;其实还是很有意思的&#xff0c;最近阿里发布了一个类似的模型&#xff0c;但是还没开源&#xff0c;从展示视频看&#xff0c;阿…

酷开科技OTT大屏营销:开启新时代的营销革命

随着互联网技术的不断发展和普及&#xff0c;大屏已经成为越来越多家庭选择的娱乐方式。在这个背景下&#xff0c;酷开科技凭借其强大的技术实力和敏锐的市场洞察力&#xff0c;成功地将大屏转化为一种新的营销渠道&#xff0c;为品牌和企业带来了前所未有的商业机会。 酷开科技…

WEB3.0:互联网的下一阶段

随着互联网的发展&#xff0c;WEB3.0时代正在逐步到来。本文将深入探讨WEB3.0的定义、特点、技术应用以及未来展望&#xff0c;为读者带来全新的思考。 一、什么是WEB3.0&#xff1f; WEB3.0可以被理解为互联网发展的下一阶段&#xff0c;是当前WEB2.0的升级版。相较于2.0时代…

CentOS 各个版本下载地址

https://mirror.nsc.liu.se/centos-store/7.6.1810/isos/x86_64/ CentOS-7-x86_64-DVD-1810.iso 2018-Nov-26 00:55:20 4.2G application/octet-stream 正常版 CentOS-7-x86_64-DVD-1810.torrent 2018-Dec-03 16:03:27 85.9K application/x-bittorrent CentOS-7-x86_64-Every…

用户系统加密--Java

一个基本的用户系统如下&#xff1a; # 定义用户类 class User:def __init__(self, name, password):self.name nameself.password password# 创建用户列表 users []# 添加新用户 def add_user(name, password):new_user User(name, password)users.append(new_user)print…

洛谷-P1596 [USACO10OCT] Lake Counting S

P1596 [USACO10OCT] Lake Counting S - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) #include<bits/stdc.h> using namespace std; const int N110; int m,n; char g[N][N]; bool st[N][N]; //走/没走 int dx[] {-1,-1,-1,0,0,1,1,1}; //八联通 int dy[] {-1,0,1,1,-1,1…

LDF、DBC、BIN、HEX、S19、BLF、ARXML、slx等

文章目录 如题 如题 LDF是LIN报文格式文件&#xff0c;把这个直接拖到软件里面&#xff0c;可以发报文和接收报文 DBC是CAN报文格式文件&#xff0c;把这个直接拖到软件里面&#xff0c;可以发报文和接收报文 BIN文件烧录在BOOT里面&#xff08;stm32&#xff09;&#xff0c…

【前端】解决前端图表大数据配色难题:利用HSL动态生成颜色方案

解决前端图表大数据配色难题&#xff1a;利用HSL动态生成颜色方案 在数据可视化项目中&#xff0c;尤其是当需要绘制包含大量数据点的图表时&#xff0c;一个常见的挑战是如何为每个数据点分配一个独特而又视觉上容易区分的颜色。使用固定的颜色列表可能在数据点数量超过列表限…

CTF-SHOW SSRF

web351 存在一个flag.php页面&#xff0c;访问会返回不是本地用户的消息&#xff0c;那肯定是要让我们以本地用户去访问127.0.0.1/flag.php web352 代码中先判断是否为HTTP或https协议&#xff0c;之后判断我们传入的url中是否含有localhost和127.0.0&#xff0c;如果没有则…

课时93:流程控制_函数进阶_综合练习

1.1.3 综合练习 学习目标 这一节&#xff0c;我们从 案例解读、脚本实践、小结 三个方面来学习。 案例解读 案例需求 使用shell脚本绘制一个杨辉三角案例解读 1、每行数字左右对称&#xff0c;从1开始变大&#xff0c;然后变小为1。    2、第n行的数字个数为n个&#xf…

Golang | Leetcode Golang题解之第24题两两交换链表中的节点

题目&#xff1a; 题解&#xff1a; func swapPairs(head *ListNode) *ListNode {dummyHead : &ListNode{0, head}temp : dummyHeadfor temp.Next ! nil && temp.Next.Next ! nil {node1 : temp.Nextnode2 : temp.Next.Nexttemp.Next node2node1.Next node2.Nex…

项目实训2024.04.12日志:Self-QA生成问答对

1. Self-QA技术 1.1. 为什么要用Self-QA技术 关于为什么要搜集问答对&#xff0c;我在创新实训2024.04.07日志&#xff1a;提取QA对这篇文章中提到过&#xff1a;训练大模型需要从业务侧积累的问题、资料、文档中提取出一些指令-问答对作为输入的语料。 之前我们对于问答对的…

ChatGPT加持,需求分析再无难题

简介 在实际工作过程中&#xff0c;常常需要拿到产品的PRD文档或者原型图进行需求分析&#xff0c;为产品的功能设计和优化提供建议。 而使用ChatGPT可以很好的帮助分析和整理用户需求。 实践演练 接下来&#xff0c;需要使用ChatGPT 辅助我们完成需求分析的任务 注意&…

【编程】C++ 常用容器以及一些应用案例

介绍一些我常用的C容器和使用方法&#xff0c;以及使用案例。blog 1 概述 容器&#xff08;Container&#xff09;是一个存储其他对象集合的持有者对象。容器以类模板实现&#xff0c;对支持的元素类型有很大的灵活性。容器管理元素的存储并提供多个成员函数来访问和操作元素…

鸿蒙OS开发学习:【第三方库调用】

介绍 本篇Codelab主要向开发者展示了在Stage模型中&#xff0c;如何调用已经上架到[三方库中心]的社区库和项目内创建的本地库。效果图如下&#xff1a; 相关概念 [Navigation]&#xff1a;一般作为Page页面的根容器&#xff0c;通过属性设置来展示页面的标题、工具栏、菜单。…

OpenHarmony编译构建系统

这篇来聊聊OpenHarmony的编译构建&#xff0c;经过前面的实践&#xff0c;再来看编译构建。 编译构建概述 在官网中提到了&#xff0c;OpenHarmony编译子系统是以GN和Ninja构建为基座&#xff0c;对构建和配置粒度进行部件化抽象、对内建模块进行功能增强、对业务模块进行功能…