当前位置: 首页 > news >正文

基础IO

重新定义 “文件”:不止于磁盘存储

理解 “文件” 是掌握 Linux 基础 IO 的首要前提,其概念在 Linux 中被广泛延伸,远超传统磁盘文件的范畴。

文件的核心构成:属性 + 内容

无论何种类型的文件,本质都是 **“文件属性(元数据)+ 文件内容”** 的集合。即使是 0KB 的空文件,也会占用磁盘空间,因为其属性(如权限、创建时间、所有者等)需要被持久化存储;对文件的所有操作,最终都可归结为对 “属性” 或 “内容” 的修改。

 从狭义到广义:Linux “一切皆文件”

狭义文件:存储在磁盘上的永久性数据文件(如文本文件、二进制文件),对这类文件的读写操作,本质是与磁盘外设进行输入输出(IO)交互。

广义文件:Linux 将键盘、显示器、网卡、进程等硬件或抽象对象均抽象为文件。例如,读取键盘输入即 “读键盘文件”,向显示器输出即 “写显示器文件”。这种抽象设计让开发者可通过一套统一 API 操作所有设备,极大降低了编程复杂度。

 系统视角:文件操作的本质是进程操作

磁盘等硬件由操作系统统一管理,用户程序无法直接访问硬件。因此,所有文件操作的本质是 “进程对文件的操作”:进程通过系统调用接口向操作系统发起请求,由操作系统完成底层硬件交互。C/C++ 中的 fopen/fwrite 等库函数,仅是对系统调用的封装,目的是简化用户编程流程。

访问文件本质是进程对文件的操作!!!

C 库函数与系统调用

Linux 提供两种核心 IO 操作接口:C 标准库 IO 函数与系统调用 IO 接口,二者层级不同但紧密关联。

C 库 IO 接口:用户层的便捷封装

C 标准库提供了一套面向 “文件流(FILE*)” 的操作函数,核心包括 fopen(打开文件)、fwrite(写文件)、fread(读文件)、fclose(关闭文件),默认维护 3 个标准流。

 核心标准流

C 程序启动时,默认打开 3 个标准文件流,类型均为 FILE*

stdin:标准输入流,对应键盘,用于读取输入数据。

stdout:标准输出流,对应显示器,用于输出正常信息。

stderr:标准错误流,对应显示器,用于输出错误信息。

常见操作示例

写文件:通过 fopen 打开文件,fwrite 循环写入数据,最后 fclose 关闭文件。

int main()
{FILE *fp = fopen("log.txt", "w");if(fp == NULL){perror("fopen");return 1;}const char *msg = "hello bit: ";int cnt = 1;while(cnt <= 10){char buffer[1024];snprintf(buffer, sizeof(buffer), "%s%d\n", msg, cnt++);fwrite(buffer, strlen(buffer), 1, fp);}fclose(fp);return 0;
}

C 语言实现的简易文件查看工具,其功能类似简化版的 cat 命令:

// cat myfile.txt
int main(int argc, char *argv[])
{if(argc != 2){printf("Usage: %s filename\n", argv[0]);return 1;}FILE *fp = fopen(argv[1], "r");if(NULL == fp){perror("fopen");return 2;}while(1){char buffer[128];memset(buffer, 0, sizeof(buffer));int n = fread(buffer, sizeof(buffer)-1, 1, fp);if(n > 0){printf("%s", buffer);}if(feof(fp))break;}fclose(fp);return 0;
}

系统调用 IO 接口:内核层的底层接口

系统调用是操作系统提供的底层 IO 接口,操作对象为文件描述符(fd),核心函数包括 open(打开 / 创建文件)、write(写文件)、read(读文件)、close(关闭文件),使用时需包含 Linux 专用头文件(如 <sys/types.h><sys/stat.h><fcntl.h>)。

open

open 函数用于打开或创建文件,有两种原型,核心参数与返回值如下:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
// 1. 打开已存在的文件
int open(const char *pathname, int flags);
// 2. 创建并打开新文件(需指定权限)
int open(const char *pathname, int flags, mode_t mode);
  • pathname:文件路径(相对路径或绝对路径)。

  • flags:打开方式标志,必须包含且仅包含 O_RDONLY(只读)、O_WRONLY(只写)、O_RDWR(读写)三者之一,可搭配以下标志:

    • O_CREAT:文件不存在时创建。

    • O_TRUNC:清空文件原有内容(如 “>” 重定向逻辑)。

    • O_APPEND:追加写入(如 “>>” 重定向逻辑)。

  • mode:文件权限(如 0644 表示所有者读 / 写,其他用户只读),仅当 flags 包含 O_CREAT 时有效。

  • 返回值:成功返回新文件的文件描述符(fd),失败返回 -1

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main()
{
umask(0);
int fd = open("iog.txt", O_WRONLY|O_CREAT, 0644);
if(fd < 0){
perror("open");
return 1;
}
int count = 5;
const char *msg = "hello bit!\n";
int len = strlen(msg);
while(count--){
write(fd, msg, len);//fd: 后⾯讲, msg:缓冲区⾸地址, len: 本次读取,期望
写⼊多少个字节的数据。 返回值:实际写了多少字节数据
}
close(fd);
return 0;
}

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main()
{
int fd = open("myfile", O_RDONLY);
if(fd < 0){
perror("open");
return 1;
}
const char *msg = "hello bit!\n";
char buf[1024];
while(1){
ssize_t s = read(fd, buf, strlen(msg));//类⽐write
if(s > 0){
printf("%s", buf);
}else{
break;
}
}
close(fd);
return 0;
}

 

文件描述符(fd)

文件描述符(File Descriptor,简称 fd)是 Linux 中标识 “打开文件” 的非负整数,是理解内核 IO 管理逻辑的核心概念。

 默认的 3 个文件描述符

Linux 进程启动时,默认打开 3 个标准文件描述符,对应 3 个标准流,且 fd 与流的对应关系固定:

fd 值对应流默认设备功能
0stdin键盘标准输入,读取外部数据
1stdout显示器标准输出,输出正常信息
2stderr显示器标准错误,输出错误信息

fd 的本质:数组下标

内核为每个进程维护一个 files_struct 结构体,该结构体包含一个 fd_array 指针数组,fd 本质是这个数组的下标。数组中的每个元素指向一个 file 结构体(存储打开文件的属性、读写位置、操作方法等核心信息)。例如,fd=1 对应的数组元素指向 “显示器文件” 的 file 结构体,因此向 fd=1 写数据会输出到显示器。

fd 的分配规则

当进程通过 open 打开新文件时,操作系统会遵循 “最小未使用下标” 原则  分配 fd:即从 fd_array 数组中找到当前未被占用的最小下标,作为新文件的 fd。

⽂件描述符的分配规则

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int fd = open("myfile", O_RDONLY);
if(fd < 0){
perror("open");
return 1;
}
printf("fd: %d\n", fd);
close(fd);
return 0;
}

输出结果为3

关闭0或者2,在看

close(0);
//close(2);
int fd = open("myfile", O_RDONLY);
if(fd < 0){
perror("open");
return 1;
}
printf("fd: %d\n", fd);
close(fd);

发现是结果是: fd: 0 或者 fd 2 ,可⻅,⽂件描述符的分配规则:在files_struct数组当中,找到

当前没有被使⽤的最⼩的⼀个下标,作为新的⽂件描述符。

重定向

close(1);
int fd = open("myfile", O_WRONLY|O_CREAT, 00644);
if(fd < 0){
perror("open");
return 1;
}
printf("fd: %d\n", fd);
fflush(stdout);
close(fd);
exit(0);

此时,我们发现,本来应该输出到显⽰器上的内容,输出到了⽂件 myfile 当中,其中,fd=1。这

种现象叫做输出重定向。常⻅的重定向有: > , >> , <

重定向的本质

http://www.dtcms.com/a/394288.html

相关文章:

  • Linux开发工具
  • DIDCTF-2023陇剑杯
  • 软件设计师软考备战:第四篇 计算机网络技术
  • 基于 GEE 利用 Sentinel-1 SAR 数据计算标准化双极化水体指数(SDWI)实现水体智能识别
  • 120-armv8_a_power_management:高级架构电源管理指南
  • 【MySQL初阶】02-库的操作
  • Kafka面试精讲 Day 20:集群监控与性能评估
  • 【C语言】数字模式求和算法的巧妙实现:深入解析循环与累加的艺术
  • 关系型数据库对比
  • 手机可视化方案(针对浓度识别)
  • LLM在应用计量经济学和因果推断中作用的思考
  • Redis 事务机制详解:从原理到实战
  • 【精品资料鉴赏】130页PPT汽车智能制造企业数字化转型SAP解决方案参考
  • 【区间贪心】P2859 [USACO06FEB] Stall Reservations S|普及+
  • Java进阶教程,全面剖析Java多线程编程,阻塞队列方式实现等待唤醒机制,笔记17
  • 【SAP小说】阿根廷项目的SAP突围:2025阿根廷平行账项目纪实
  • 具有广泛宿主范围的噬菌体在生态系统中很常见
  • 【Linux】进程概念(四):Linux进程优先级与进程调度的核心逻辑
  • @ModelAttribute 和@RequestBody有什么区别
  • npm玩转技巧
  • 柔性精密测量技术在小型化载荷微小应变监测方面的应用
  • 命令注入(Command Injection)漏洞学习笔记
  • 268-基于Django的热门游戏榜单数据分析系统
  • C++篇 类和对象(2)万能工具怎么用?
  • MySQL 多实例部署与主从、读写分离配置
  • C++初阶(10)string类
  • 高性能开源 Web 服务器软件--Nginx
  • 软考中级习题与解答——第十章_多媒体技术(2)
  • 【字符串】1.最⻓公共前缀(easy)
  • 新闻源发稿平台推荐,企业形象宣传新闻源收录平台