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

Linux | 探究C语言文件接口与Linux系统文件接口的区别与联系 | fopen和open的区别与联系

什么是尘土?从大地之肺发出的一声叹息。 - 《阿多尼斯诗集》(阿多尼斯)

2024.8.23

目录

1、C语言IO接口

示例代码:使用 fopen 和 fclose 读写文件

示例1:通过write写文件

示例2:通过read写文件

C语言的标准流:stdin、stdout和stderr

stdin (标准输入流)

stdout (标准输出流)

stderr (标准错误流)

标准流总结:

示例代码:使用标准流与外部设备进行设备交互

2、Linux系统IO接口与库函数

系统IO接口介绍:open

参数说明

返回值

注意事项

示例代码:使用系统调用进行文件操作

示例1:通过系统调用接口write写文件

示例2:用过系统调用接口read读文件

3、C语言IO接口和Linux系统IO接口的区别与联系

区别

抽象级别:

可移植性:

功能丰富性:

联系

封装关系:

共同目标:

互操作性:

文件描述符:

底层支持:


在C语言编程中,文件IO操作是基础而重要的部分。通过文件IO,程序能够读取外部数据或将结果持久化存储。

1、C语言IO接口

C语言提供了丰富的文件操作API,基于标准库中的 <stdio.h> 头文件。最常用的文件操作包括打开、读取、写入、关闭文件等。

示例代码:使用 fopenfclose 读写文件
示例1:通过write写文件
#include<stdio.h>
#include<string.h>
// 通过write写文件
int main()
{FILE* fp = fopen("test.txt", "a");if(!fp){printf("file open fail\n");return -1;}const char* msg = "hello world\n";int len = strlen(msg);int count = 10;while(count--){fwrite(msg, 1, len, fp);}fclose(fp);return 0;
}
示例2:通过read写文件
#include<stdio.h>
#include<string.h>
#define MAX 1024
// 通过read写文件
int main()
{FILE* fp = fopen("test.txt", "r");if(!fp){printf("[error] file open fail\n");return -1;}int cnt = 0;char buf[MAX];const char* msg = "hello world\n";while(1){cnt++;if(feof(fp)){break;}printf("cnt -> %d\n",cnt);size_t size = fread(buf, 1, strlen(msg), fp);printf("%s\n", buf);}fclose(fp); return 0;
}

C语言的标准流:stdin、stdout和stderr
stdin (标准输入流)
  • 类型FILE*
  • 作用:用于从键盘或另一个输入设备读取数据。
  • 文件指针:通常指向文件描述符 0
stdout (标准输出流)
  • 类型FILE*
  • 作用:用于向控制台或终端输出数据。
  • 文件指针:通常指向文件描述符 1
stderr (标准错误流)
  • 类型FILE*
  • 作用:用于向控制台或终端输出错误信息。与 stdout 不同,stderr 通常用于输出错误或诊断信息,即使程序的输出被重定向,错误信息仍然会显示在终端上。
  • 文件指针:通常指向文件描述符 2
标准流总结:
  • 全局性:在任何C程序中,无需打开即可使用。
  • 缓冲stdoutstderr 通常具有不同的缓冲行为。stdout 可能是行缓冲或全缓冲,而 stderr 通常是无缓冲的。也就是说,stdout 可能不会立即输出内容,但 stderr 是为了快速错误报告而设计的,通常会立即输出。
  • 重定向:可以通过简单的重定向操作改变它们的输出目标,例如在 shell 中使用 >2> 将输出重定向到文件。
  • 可以通过 fileno 函数获取 FILE* 指针对应的文件描述符,例如 fileno(stdin) 将返回 0
  • 在多线程程序中,stdoutstderr 不是线程安全的,但 stderr 在写入时通常会被锁定以避免与其他线程冲突。
示例代码:使用标准流与外部设备进行设备交互
#include <stdio.h>int main() {char buffer[256];// 使用 stdin 读取键盘数据printf("Enter some text: ");fgets(buffer, sizeof(buffer), stdin);// 使用 stdout 向显示器输出数据fprintf(stdout, "You entered: %s\n", buffer);// 使用 stderr 向显示器输出错误信息fprintf(stderr, "This is an error message.\n");return 0;
}

2、Linux系统IO接口与库函数

系统调用是操作系统提供给用户程序的接口,而库函数则是对这些系统调用的封装,使得程序员可以使用更高级、更易用的API。

系统IO接口介绍:open

在Linux系统中,open 系统调用是一个用于打开文件或创建新文件的标准函数。它提供了一种底层的方法来操作文件,与C标准库中的 fopen 函数相比,open 函数更接近操作系统层面,允许更细致地控制文件的打开方式和属性。

#include <sys/types.h>  // 包含系统类型定义
#include <sys/stat.h>   // 包含文件状态结构定义
#include <fcntl.h>      // 包含文件控制选项定义int open(const char *pathname, int flags, ... /* mode_t mode */);
参数说明
  1. pathname:这是一个指向以null结尾的字符串的指针,表示要打开或创建的文件的路径。
  2. flags:这是一个整数,用于指定文件打开的各种选项和模式。可以是以下宏的组合:
    • O_RDONLY:以只读方式打开文件。
    • O_WRONLY:以只写方式打开文件。
    • O_RDWR:以读写方式打开文件。
    • O_CREAT:如果文件不存在,创建新文件。
    • O_EXCL:与 O_CREAT 一起使用时,如果文件已存在,则 open 调用失败。
    • O_TRUNC:如果文件存在,将其截断为零长度。
    • O_APPEND:所有写操作都追加到文件末尾,忽略 lseekllseek 设置的文件偏移量。
    • 等等,还有其他标志位用于更特殊的用途。
  3. mode(可选):当使用 O_CREAT 标志时,这个参数指定新创建文件的权限模式。如果不提供,则默认权限由进程的 umask 值决定(就近原则)。
返回值
  • 成功时,open 函数返回一个非负的文件描述符(fd),用于在后续操作中标识打开的文件。
  • 失败时,返回 -1,并设置全局变量 errno 以指示错误类型。
注意事项
  • open 函数返回的文件描述符(fd)可以用于后续的 readwritelseek 等系统调用。
  • 使用 open 打开的文件应该在不再需要时使用 close 函数关闭,以释放系统资源。
  • open 函数支持的 flags 标志位非常灵活,可以根据需要组合使用不同的标志来控制文件的打开方式。
  • fopen 不同,open 没有提供缓冲机制。如果需要缓冲,可以使用标准IO库中的缓冲函数,或者手动实现缓冲逻辑。

write、read、close和C语言接口类似 不多介绍啦~

示例代码:使用系统调用进行文件操作
示例1:通过系统调用接口write写文件
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>int main() {// 设置文件的默认权限掩码,创建文件时忽略进程的umask设置umask(0);// 打开文件,O_WRONLY 只写模式,O_CREAT 如果文件不存在则创建,0644 是文件的默认权限int fd = open("myfile", 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 系统调用,将 msg 缓冲区中 len 大小的数据写入到文件描述符 fd 指向的文件// 返回值是实际写入的字节数ssize_t bytes_written = write(fd, msg, len);if (bytes_written < 0) {perror("write");close(fd);return 1;}}// 关闭文件描述符close(fd);return 0;
}
示例2:用过系统调用接口read读文件
#include <stdio.h>      // 包含标准输入输出库
#include <sys/types.h>  // 包含系统类型定义
#include <sys/stat.h>   // 包含文件状态结构定义
#include <fcntl.h>      // 包含文件控制选项定义
#include <unistd.h>     // 包含Unix标准函数定义,如read和close
#include <string.h>     // 包含字符串函数定义int main() {// 尝试以只读方式打开文件"myfile"int fd = open("myfile", O_RDONLY);if (fd < 0) {// 如果打开失败,打印错误信息并退出程序perror("open");return 1;}// 定义要读取的字符串长度,这里假设与写入时相同const char *msg = "hello bit!\n";size_t msg_len = strlen(msg);char buf[1024]; // 定义一个缓冲区用于存储读取的数据// 使用循环来读取文件,直到文件结束while (1) {// 调用read系统调用尝试从文件描述符fd中读取msg_len长度的数据到缓冲区bufssize_t s = read(fd, buf, msg_len);if (s > 0) {// 如果读取成功,打印缓冲区的内容printf("%s", buf);} else {// 如果读取到文件末尾或发生错误,退出循环break;}}// 关闭文件描述符close(fd);return 0; // 正常退出程序
}

3、C语言IO接口和Linux系统IO接口的区别与联系

C语言IO接口和Linux系统IO接口是两个层面的抽象,它们之间存在明显的区别和紧密的联系:

区别
抽象级别
    • C语言IO接口(如 fopenfclosefreadfwrite 等)是C标准库提供的功能,它们是对底层系统IO操作的高层次抽象。
    • Linux系统IO接口(如 openclosereadwrite 等)是直接由操作系统内核提供的系统调用,提供了对硬件的直接操作能力。
可移植性
    • C语言IO接口具有良好的可移植性,因为它们由编译器和标准库实现,可以在不同的操作系统上运行。
    • Linux系统IO接口是特定于操作系统的,只能在支持这些系统调用的系统上使用。
功能丰富性
    • C语言IO接口提供了更多格式化和方便的函数,如 fprintffgets 等,简化了编程。
    • Linux系统IO接口提供了基础的读写操作,但通常需要程序员进行更多的底层管理。
联系
封装关系
    • C语言IO接口实际上是对Linux系统IO接口的封装。例如,当你使用 fopen 打开一个文件时,C库内部会使用 open 系统调用来获取文件描述符。
共同目标
    • 两者都旨在提供对文件和输入输出流的操作能力,尽管抽象级别不同。
互操作性
    • 程序员可以在使用C语言IO接口的同时,通过特定的函数(如 fileno)获取到底层的文件描述符,并使用Linux系统IO接口进行操作。
文件描述符
    • 无论是使用C语言IO接口还是Linux系统IO接口,最终都可能与文件描述符(fd)打交道。例如,fopen 返回的 FILE* 类型内部包含了一个文件描述符。
底层支持
    • C语言IO接口的实现依赖于操作系统提供的底层支持,如Linux的系统调用来完成实际的文件操作。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • vue预览全景图片
  • 【设计模式之原型模式——矩形原型】
  • javacv-ffmpeg ProcessBuilder实现对图片的旋转
  • 【MySQL数据库管理问答题】第1章 MySQL 简介
  • 一文讲清协同过滤,矩阵分解,spark als,显示反馈与隐式反馈
  • 蓝牙耳机百元内怎么选?四款上榜百元品牌机型合集
  • HTB-Explosion(rdp连接)和preignition(目录遍历)
  • 外包干了2年,女朋友跑了...
  • 【Linux】基本命令(第二篇)
  • 【系统分析师】-综合知识-计算机网络与信息安全
  • 无损放大图片,盘点5款最新无损放大图片软件
  • Python和MATLAB和R对比敏感度函数导图
  • Redis单线程和多线程
  • YOLOv8目标检测部署RK3588全过程,附代码pt->onnx->rknn,附【详细代码】
  • Apache Doris 使用 CBO 和 RBO 结合的优化策略
  • 【347天】每日项目总结系列085(2018.01.18)
  • egg(89)--egg之redis的发布和订阅
  • JS 面试题总结
  • js中的正则表达式入门
  • open-falcon 开发笔记(一):从零开始搭建虚拟服务器和监测环境
  • thinkphp5.1 easywechat4 微信第三方开放平台
  • Vue ES6 Jade Scss Webpack Gulp
  • 初识MongoDB分片
  • 高程读书笔记 第六章 面向对象程序设计
  • 记录一下第一次使用npm
  • 扑朔迷离的属性和特性【彻底弄清】
  • 前端每日实战 2018 年 7 月份项目汇总(共 29 个项目)
  • 事件委托的小应用
  • LIGO、Virgo第三轮探测告捷,同时探测到一对黑洞合并产生的引力波事件 ...
  • 哈罗单车融资几十亿元,蚂蚁金服与春华资本加持 ...
  • ​​​​​​​​​​​​​​汽车网络信息安全分析方法论
  • #中的引用型是什么意识_Java中四种引用有什么区别以及应用场景
  • $分析了六十多年间100万字的政府工作报告,我看到了这样的变迁
  • (HAL)STM32F103C6T8——软件模拟I2C驱动0.96寸OLED屏幕
  • (PyTorch)TCN和RNN/LSTM/GRU结合实现时间序列预测
  • (Redis使用系列) Springboot 使用Redis+Session实现Session共享 ,简单的单点登录 五
  • (读书笔记)Javascript高级程序设计---ECMAScript基础
  • (多级缓存)多级缓存
  • (仿QQ聊天消息列表加载)wp7 listbox 列表项逐一加载的一种实现方式,以及加入渐显动画...
  • (附源码)ssm经济信息门户网站 毕业设计 141634
  • (附源码)ssm旅游企业财务管理系统 毕业设计 102100
  • (附源码)流浪动物保护平台的设计与实现 毕业设计 161154
  • (含react-draggable库以及相关BUG如何解决)固定在左上方某盒子内(如按钮)添加可拖动功能,使用react hook语法实现
  • (学习日记)2024.03.25:UCOSIII第二十二节:系统启动流程详解
  • (一)eclipse Dynamic web project 工程目录以及文件路径问题
  • (转)总结使用Unity 3D优化游戏运行性能的经验
  • .net core docker部署教程和细节问题
  • .NET Framework与.NET Framework SDK有什么不同?
  • .Net 执行Linux下多行shell命令方法
  • .Net--CLS,CTS,CLI,BCL,FCL
  • .net项目IIS、VS 附加进程调试
  • .net知识和学习方法系列(二十一)CLR-枚举
  • @hook扩展分析
  • @WebServiceClient注解,wsdlLocation 可配置
  • [ IOS ] iOS-控制器View的创建和生命周期