数据结构day7——文件IO

一、标准 IO 的起源与概念

标准 IO(Standard Input/Output)是由 Dennis Ritchie 在 1975 年设计的一套 IO 库,后来成为 C 语言的标准组成部分,并被 ANSI C 所采纳。它是对底层文件 IO 的封装,提供了更便捷、可移植的文件操作接口。

核心特点:

  • 设备抽象:将输入输出设备抽象为文件操作
    • 标准输入设备:默认是键盘(/dev/input
    • 标准输出设备:默认是显示器
  • 跨平台性:任何支持标准 C 的系统都可使用
  • 缓冲机制:在用户程序和文件 IO 之间加入缓冲区,减少系统调用次数,提高效率

在 Linux 系统中,一切皆文件,IO 操作本质上都是对文件的操作。标准 IO 作为 C 语言标准库的一部分,为文件操作提供了统一接口。

二、文件的基本概念

1. 文件的作用

文件是 Linux 系统中存储数据(包括普通数据和指令)的基本单位,是数据持久化的载体。

2. Linux 文件类型(7 种)

  • d:目录文件
  • -:普通文件
  • l:链接文件(link)
  • p:管道文件(pipe)
  • s:套接字文件(socket)
  • c:字符设备文件
  • b:块设备文件

可通过ls -l命令查看文件类型,第一个字符即表示文件类型。

3. 文件内容分类

  • 文本文件:由 ASCII 字符组成,可直接阅读
  • 二进制文件:由二进制数据组成,通常需要特定程序解析

三、IO 的分类

1. 标准 IO

  • 是 ANSI C 设计的一组封装了文件 IO 的库函数
  • 头文件:stdio.h(位于/usr/include/stdio.h
  • 实现方式:stdio.hstdio.clibc.so(动态库,位于/usr/lib
  • 特点:带缓冲机制,可移植性好

2. 文件 IO

  • 属于系统调用,是底层操作接口
  • 特点:无缓冲,直接与内核交互,效率高但使用复杂

四、头文件引用方式

  • #include <stdio.h>:引用系统库函数头文件

    • 搜索路径:系统默认路径(如/usr/include/
  • #include "xxx.h":引用用户自定义头文件

    • 搜索路径:当前目录

五、流(Stream)的概念

流是数据从文件流入和流出所体现的字节序列,在标准 IO 中用FILE*指针表示(称为流对象或文件流指针)。

1. 流的分类

  • 二进制流:由二进制数据组成的流
  • 文本流:由 ASCII 码数据组成的流

2. 标准流

C 语言默认打开三个标准流:

  • stdin:标准输入流(对应键盘)
  • stdout:标准输出流(对应显示器)
  • stderr:标准错误流(对应显示器)

六、缓冲区机制

标准 IO 的一大特点是采用缓冲机制,目的是减少系统调用,提高效率。

1. 缓冲区类型

  • 行缓冲(1KB)

    • 应用场景:主要用于终端交互(如stdout
    • 刷新条件:遇到\n、缓冲区满、程序正常结束、fflush()强制刷新
  • 全缓冲(4KB)

    • 应用场景:主要用于普通文件操作
    • 刷新条件:缓冲区满、程序正常结束、fflush()强制刷新
  • 无缓冲(0KB)

    • 应用场景:主要用于错误处理(如stderr
    • 特点:数据直接输出,不经过缓冲

2. 缓冲区操作函数

  • fflush(FILE *stream):强制刷新缓冲区

七、标准 IO 常用函数

1. 文件打开与关闭

  • fopen():打开文件并建立流

    FILE *fopen(const char *path, const char *mode);
    
     
    • mode参数:
      • r:只读(文件不存在则报错)
      • r+:读写(文件不存在则报错)
      • w:只写(文件不存在则创建,存在则清空)
      • w+:读写(文件不存在则创建,存在则清空)
      • a:追加写(文件不存在则创建)
      • a+:追加读写(文件不存在则创建)
  • fclose():关闭文件流

    int fclose(FILE *stream);
    

2. 字符操作函数

  • fgetc(FILE *stream):从流中读取一个字符
  • fputc(int c, FILE *stream):向流中写入一个字符
  • getchar():从标准输入读取一个字符(fgetc(stdin)的宏定义)
  • putchar(int c):向标准输出写入一个字符(fputc(c, stdout)的宏定义)

示例:实现简单的输入输出循环

while(1)fputc(fgetc(stdin), stdout);

3. 行操作函数

  • fgets(char *s, int size, FILE *stream):从流中读取一行数据

    char *fgets(char *s, int size, FILE *stream);
    
     
    • 最多读取size-1个字符,自动添加\0
    • 遇到\n会停止读取,且\n会被包含在结果中
  • fputs(const char *s, FILE *stream):向流中写入一行数据

    int fputs(const char *s, FILE *stream);
    
  • gets()/puts():与fgets()/fputs()类似,但gets()没有缓冲区大小限制,存在安全隐患

4. 块操作函数(二进制操作)

  • fread():从流中读取指定大小的数据块

    size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
    
  • fwrite():向流中写入指定大小的数据块

    size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
    

示例:结构体读写

struct person {char name[20];int age;char sex;char addr[100];
};struct person p = {"Tom", 20, 'M', "Beijing"};
fwrite(&p, sizeof(struct person), 1, fp);

5. 文件定位函数

  • fseek():移动文件指针

    int fseek(FILE *stream, long offset, int whence);
    
     
    • whence参数:
      • SEEK_SET:从文件开头
      • SEEK_CUR:从当前位置
      • SEEK_END:从文件末尾
  • ftell():获取当前文件指针位置

    long ftell(FILE *stream);
    
  • rewind():将文件指针移到开头(等效于fseek(stream, 0L, SEEK_SET)

    void rewind(FILE *stream);
    

6. 其他常用函数

  • printf()/scanf():格式化输入输出
  • sprintf():将格式化数据写入字符串
  • feof():判断文件是否到达末尾
  • ferror():检测流是否出错
  • clearerr():清除流出错标记

八、标准 IO 操作流程

  1. 打开文件:使用fopen()获取文件流指针(FILE*
  2. 读写操作:根据需求选择合适的 IO 函数(字符、行、块操作)
  3. 关闭文件:使用fclose()关闭文件流,释放资源

九、实践练习

1. 实现简易cat程序

#include <stdio.h>int main(int argc, char *argv[]) {FILE *fp;int c;if (argc != 2) {fprintf(stderr, "Usage: %s filename\n", argv[0]);return 1;}fp = fopen(argv[1], "r");if (fp == NULL) {fprintf(stderr, "Cannot open file %s\n", argv[1]);return 1;}while ((c = fgetc(fp)) != EOF) {fputc(c, stdout);}fclose(fp);return 0;
}

2. 实现文件拷贝功能

#include <stdio.h>
#include <stdlib.h>#define BUFFER_SIZE 1024int main(int argc, char *argv[]) {FILE *src, *dest;char buffer[BUFFER_SIZE];size_t n;if (argc != 3) {fprintf(stderr, "Usage: %s source destination\n", argv[0]);return 1;}src = fopen(argv[1], "rb");if (src == NULL) {fprintf(stderr, "Cannot open source file %s\n", argv[1]);return 1;}dest = fopen(argv[2], "wb");if (dest == NULL) {fprintf(stderr, "Cannot open destination file %s\n", argv[2]);fclose(src);return 1;}while ((n = fread(buffer, 1, BUFFER_SIZE, src)) > 0) {fwrite(buffer, 1, n, dest);}fclose(src);fclose(dest);return 0;
}

十、man 手册的使用

man 手册是查询函数和命令的重要工具,分为不同章节:

  • man 1 xxx:查看命令帮助
  • man 2 xxx:查看系统调用函数
  • man 3 xxx:查看标准库函数

例如:

  • man 3 fopen:查看 fopen 函数的详细说明
  • man 3 printf:查看 printf 函数的用法

总结

标准 IO 是 C 语言中处理文件操作的重要接口,通过缓冲机制提高了 IO 效率,同时提供了丰富的函数族满足不同场景的需求。掌握标准 IO 的使用,对于 C 语言程序开发至关重要。从基本的字符读写到复杂的文件定位,标准 IO 都提供了简洁而强大的解决方案,是每个 C 程序员必须掌握的基础知识。

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

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

相关文章

6.Docker部署ES+kibana

部署ES&#xff08;Elasticsearch&#xff09;kibana 1.ES暴露的端口很多 2.ES十分消耗内存 3.ES的数据一般需要挂载出去&#xff0c;放在安全目录&#xff08;挂载) elastic 前往官方手册 1.下载运行elasticsearch的 docker run -d --name elasticsearch --net somenet…

使用mysqldump对mysql数据库进行备份

目录 1软件说明 2语法格式 3备份流程 3.1只备份指定数据库中表和数据 3.1.1准备目录 3.1.2备份db1数据库里面的所有表信息 3.1.3还原备份 3.2备份数据库结构 3.2.1备份db1数据库的结构和数据 3.2.2还原数据库 3.3备份所有数据库 3.3.1备份数据库 3.3.2还原数据库 1…

vue3路由跳转打开新页面

Vue3 路由跳转打开新页面的方法 在 Vue3 中&#xff0c;有几种方法可以实现路由跳转时打开新页面&#xff1a; 1. 使用 router.resolve 方法 import { useRouter } from vue-routerconst router useRouter()const openNewPage (path) > {const resolved router.resolv…

SeaTunnel 社区 2 项目中选“开源之夏 2025”,探索高阶数据集成能力!

Apache SeaTunnel 社区在“开源之夏 2025”中再传捷报&#xff0c;共有两个项目成功入选&#xff0c;聚焦于 Flink CDC schema 支持与元数据管理的生态扩展方向&#xff0c;体现出 SeaTunnel 在实时数据集成和平台化能力构建上的深入布局。 中选项目与学生如下&#xff1a; 《…

Neo4j无法建立到 localhost:7474 服务器的连接出现404错误

一、确认中文路径问题&#xff08;核心原因&#xff09; 安装路径包含中文&#xff0c;可能导致 Windows 命令行或 Neo4j 解析路径时出错。 解决方法&#xff1a; 重新安装 Neo4j 到英文路径&#xff08;推荐&#xff09;&#xff1a; 将 Neo4j 解压或安装到不含中文的目录&a…

锂离子电池均衡拓扑综述

锂离子电池均衡拓扑综述 一、引言 锂离子电池因其高能量密度、长循环寿命等优点&#xff0c;在电动汽车、储能系统等领域得到了广泛应用。然而&#xff0c;电池组在使用过程中&#xff0c;由于电池个体差异、充放电管理等因素&#xff0c;会出现荷电状态&#xff08;SOC&…

[面试] 手写题-浅拷贝,深拷贝

浅拷贝 // 浅拷贝 function shallow(obj) {const newObj {}for (const key in obj) {// 保证 key 不是原型的属性if (obj.hasOwnProperty(key)) {newObj[key] obj[key]}}return newObj }深拷贝 递归 O(n^2) // 深拷贝 function deepClone(obj {}) {// 如果传入的是 null&am…

BehaviorTree.ROS2安装记录

坑比库&#xff0c; 首先 git clone https://github.com/BehaviorTree/BehaviorTree.ROS2.git 依赖 git clone https://github.com/PickNikRobotics/cpp_polyfills.git git clone https://github.com/PickNikRobotics/RSL.git git clone https://github.com/PickNikRobotics/…

Vue基础(19)_Vue内置指令

我们学过的vue内置指令&#xff1a; v-bind&#xff1a;单向绑定解析表达式&#xff0c;可简写为&#xff1a;:xxx v-model&#xff1a;双向数据绑定 v-for&#xff1a;遍历数组/对象/字符串 v-on&#xff1a;绑定事件监听&#xff0c;可简写为 v-if&#xff1a;条件渲染(动态控…

排列组合初步

什么是排列组合 排列组合是计数问题&#xff0c;顺序不同且值相同算两种方案是排列&#xff0c;顺序不同且值相同算一种方案是组合。 暴力枚举方案能算出方案数&#xff0c;太耗时&#xff0c;运用加法原理和乘法原理可降低时间复杂度。先将原问题拆解成子问题&#xff0c;根…

SQL调优方案对比与最佳实践

问题背景介绍 在大型互联网或企业级应用中&#xff0c;数据库往往成为系统性能的瓶颈。随着数据量和并发量的增长&#xff0c;单一的 SQL 查询可能出现响应迟缓、锁等待、全表扫描等性能问题。为保证系统的稳定性和用户体验&#xff0c;需要对 SQL 查询做深入的调优。常见的调…

Terraform Helm:微服务基础设施即代码

&#x1f680; Terraform & Helm&#xff1a;微服务基础设施即代码 &#x1f4da; 目录 &#x1f680; Terraform & Helm&#xff1a;微服务基础设施即代码1. 引言 &#x1f680;2. 环境与依赖 &#x1f9f0;3. 架构示意 &#x1f3d7;️4. Terraform 定义云资源 &…

清理 Docker 缓存占用

Docker 缓存主要包括未使用的镜像、容器、卷和网络等资源。清理缓存可以提高磁盘空间&#xff0c;线上升级次数比较多的话&#xff0c;服务器中Docker缓存会非常严重&#xff0c;做下清理瘦身会有意想不到的效果 清理未使用的镜像 运行以下命令删除未被任何容器引用的镜像&…

深入解析NumPy的核心函数np.array()

深入解析NumPy的核心函数np.array NumPy与np.array()简介NumPy的重要性np.array()的作用 np.array()函数的详细参数object参数dtype参数copy参数order参数subok参数ndmin参数like参数 np.array()函数的使用示例创建基本的一维和二维数组创建具有特定数据类型的数组创建多维数组…

定时器的设计

定时器 定时器原理如何理解定时器定时器数据结构选取定时器触发方式 定时器的实现 定时器原理 如何理解定时器 定时器在日常通常被描述为组织大量延时任务的模块&#xff0c;其实从字面意思去理解的话&#xff0c;他就是去处理延时任务的&#xff0c;那么什么是延时任务呢&am…

大模型-分布式论文一瞥

1分离式架构 1.1 DistServe DistServe: Disaggregating Prefill and Decoding for Goodput-optimized Large Language Model Serving DistServe: Disaggregating Prefill and Decoding for Goodput-optimized Large Language Model Serving 讲的是一个将prefill和decoding分…

02.SpringBoot常用Utils工具类详解

文章目录 1. BeanUtils详解1.1 什么是BeanUtils&#xff1f;1.2 主要的BeanUtils实现1.2.1 Spring BeanUtils1.2.2 Apache Commons BeanUtils1.2.3 其他实现 1.3 Spring BeanUtils详细使用1.3.1 基本用法1.3.2 指定忽略属性1.3.3 批量拷贝&#xff08;列表转换&#xff09; 1.4…

Golang快速开发框架——项目立项与系统配置读取组件viper(一)

Golang快速开发框架——项目立项与系统配置读取组件viper&#xff08;一&#xff09; 背景 知识分享之Golang篇是我在日常使用Golang时学习到的各种各样的知识的记录&#xff0c;将其整理出来以文章的形式分享给大家&#xff0c;来进行共同学习。欢迎大家进行持续关注。 知识分…

打造可观测的 iOS CICD 流程:调试、追踪与质量保障全记录

随着iOS项目复杂度增加&#xff0c;团队越来越依赖自动化构建、自动化测试等CI/CD流程来保证产品质量。但CI/CD环境下&#xff0c;很多线下调试手段无法直接使用&#xff0c;比如&#xff1a; 无法手动连真机跑Instruments测试包只在分发后才能拿到崩溃模拟器上表现和真机不一…

C++11中 <cinttypes>的入门与精通

文章目录 一、<cinttypes> 是什么1. 固定宽度的整数类型2. 整数操作函数3. 格式化输入输出宏 二、深入理解 <cinttypes>1. 固定宽度整数类型的使用2. 整数操作函数的使用3. 格式化输入输出宏的使用 三、实践和技巧1. 使用固定宽度整数类型的最佳实践2. 使用整数操作…