Linux文件I/O

news2024/11/20 11:19:55

下面的内容需要了解系统调用,可看下面的链接:

系统调用来龙去脉-CSDN博客

1.底层文件IO和标准IO

这里指的是操作系统提供的IO服务,不同于ANSI建立的标准IO。

底层IO和标准IO各自所使用的函数:

区别:

1.底层文件IO不带用户级缓存,称为unbuffered I/O,每次操作都会执行相关系统调用,这一过程系统消耗资源大,而且时间也比较长。

而标准IO则带有三种缓冲机制,可以对缓冲区进行访问,必要时再访问实际文件,也就是说这时才会执行系统调用,减少了开销。

(1)全缓存
当填满I/O缓存后才进行实际I/O操作
(2)行缓存
当在输入和输出中遇到新行符(‘\n’)时,进行I/O操作。
当流遇到一个终端时,典型的行缓存。
(3)不带缓存
标准I/O库不对字符进行缓冲,例如stderr。
 

2.底层I/O特定于操作系统,只能在某些操作系统才能使用,而标准IO具有一定的移植性,只要有标准IO库就能使用。

但也不是说标准I/O一定比底层I/O好,因为缓冲的机制,我们必须时刻注意内容是否已经被冲刷过去,也就是说内容可能还在缓冲里存着,必须掌握这一缓冲机制,程序才能向我们想象的目标去完成。

2.文件描述符的介绍

Linux系统一切皆文件,Linux操作系统不区分套接字和文件。

Linux操作系统给文件或套接字分配整数,用来标识文件或者套接字,称为文件描述符(File descriptor)。因此,程序中套接字可以像文件一样来进行输入输出。

实际上,标准输入输出及标准错误在Linux中也配分配文件描述符。

文件和套接字一般经过创建过程才会被分配文件描述符。而标准输入输出及标准错误即使未经过特殊的创建过程,程序开始运行后也会被自动分配文件描述符。如下:

3.底层文件I/O函数

为了方便我们查看下面的函数调用具体发生那些错误,可看下面的链接:

errno变量和显示错误信息-CSDN博客

(1)打开文件

int open(const char *pathname,int flags);
int open(const char *pathname,int flags,mode_t mode);
//path 文件名的字符串地址,保存的是目标文件及路径信息
//flags 文件打开模式信息
//mode 文件的权限
//成功返回文件描述符,失败时返回-1,同时errno变量被设置。

flags 有以下的几个值:

flags值
O_RDONLY 只读打开
O_WRONLY只写打开
O_RDWR读写打开
O_CREAT必要时创建文件
O_TRUNC删除文件全部现有内容,从头开始写入
O_APPEND维持文件现有内容,在内容末尾追加
O_EXCL如果文件存在则出错,和O_CREAT搭配使用
O_NONBLOCK设置为非阻塞模式

打开模式参数可以通过位或运算符 ” | " 组合传递。

另外创建文件时,可能需要指定文件权限。

mode为四位八进制的数,例如mode=0644,第一个0表示八进制,文件权限根据后三位为你想要设置该文件的权限,它会与umask取反后的数相与,得到的最终结果为文件的权限。

文件权限=mode&~umask

umask通过命令umask可以查看:

(2)关闭文件

int close(int fd);
//fd 需要关闭的文件描述符,
//fd含义即上面说的file descriptor文件描述符
//成功时返回0,失败时返回-1,同时errno变量被设置。

(3)传输数据

ssize_t write(int fd,const void *buf,size_t count);
//fd 要写入对象的文件描述符
//buf 要写入数据的缓存地址值
//count 要写的字节数
//成功时返回写入的字节数,失败返回-1,同时errno变量被设置。
//通过此函数向fd指定的文件或者套接字写入buf里nbytes个字节的数据

后缀_t意味着type/typedef(类型),是一种命名规范。
size_t是通过typedef声明的unsigned int类型,表示字节数不能为负,
size中文意思尺寸大小,不能为负
ssize_t在size_t的前面加了s,表示ssize_t是通过typedef声明的signed int类型

(4)读取数据(read函数)

ssize_t read(int fd,void *buf,size_t nbytes);
//fd  需要读取数据对象的文件描述符
//buf 接收数据的缓冲地址值
//nbytes 要接受数据的最大字节数
//实际读取的字节数可能小于nbytes要求的字节数
//成功时返回接收的字节数,失败时返回-1,同时errno变量被设置。
//通过此函数将fd指定的文件或套接字读取nbytes个字节到buf里面

(5)移动读写指针

off_t lseek(int fd, off_t offset, int whence);
//fd 文件描述符
//offset 距离whence的偏移量

//whence 有三个参数选择:
//SEEK_SET:文件的头部
//SEEK_CUR:当前文件流指针的位置
//SEEK_END:文件的尾部

//通过此函数将读写指针移动到相应的位置,注意上面的write和read函数都是从指针处开始执行的
//例如下面的代码如果将lseek函数注释掉,则buf2里面没有读取到fd里面的数据。
//因为我们写完指针在fd文件里面的末尾,而末尾后面根本没有字节可以读取

//当lseek执行成功时,它会返回最终以文件起始位置为起点的偏移位置。如果出错,则返回-1,同时errno被
//设置为对应的错误值。

简单的示例代码:

//low_io.c
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>

void error_handling(const char *message)
{
        fputs(message,stderr);
        fputc('\n',stderr);
        exit(1);
}

int main(int argc,char *argv[])
{
        char buf1[]="hello,world";
        char buf2[20];

        int fd=open("data666.txt",O_RDWR|O_TRUNC);
        if(fd==-1)
                error_handling("open error!\n");
        printf("file descriptor is %d\n",fd);

        int len1=0;
        int len2=0;

        if((len1=write(fd,buf1,sizeof(buf1)))==-1)
                error_handling("write error!");
        printf("write len is %d\n",len1);
        
        lseek(fd,0,SEEK_SET);
        if((len2=read(fd,buf2,sizeof(buf2)))==-1)
                error_handling("read error!");
        printf("read len is %d\n",len2);

        fputs(buf2,stdout);
        fputc('\n',stdout);
        close(fd);
        return 0;
}

结果:

4.验证深入文件I/O和标准I/O

先分别用标准I/O和文件I/O分别写一个程序,该程序复制一个文件。

标准I/O:

//stdcopy.c
#include<error.h>
#include<stdlib.h>
#include<stdio.h>

int main(int argc,char *argv[])
{
    if(argc!=3)
    {   
        printf("<file1 file2>\n");
        exit(1);
    }   

    FILE* fp1=fopen(argv[1],"r");
    if(!fp1)
    {   
        perror("cp1.txt open failed");
        exit(1);
    }   

    FILE* fp2=fopen(argv[2],"w");
    if(!fp2)
    {   
        perror("cp2.txt open failed");
        exit(1);
    }

    while(1)
    {
        int ch=fgetc(fp1);
        if(ch==-1)
        {
            printf("end of file\n");
            break;
        }
        fputc(ch,fp2);
    }

    return 0;
}

文件I/O:

//filecopy.c
#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>

#define N 1

char buf[N];

int main(int argc,char *argv[])
{
    if(argc!=3)
    {
        printf("<file1 file2>\n");
        exit(1);
    }

    int fd1=open(argv[1],O_RDONLY);
    if(fd1==-1)
    {
        perror("fd1 open failed");
        exit(1);
    }   

    int fd2=open(argv[2],O_WRONLY|O_CREAT|O_TRUNC);
    if(fd1==-1)
    {
        perror("fd2 open failed");
        exit(1);
    }

    int readLen=0;
    while(readLen=(read(fd1,buf,N)))
    {
        if(readLen==-1)
        {
            perror("read error");
            exit(1);
        }
        write(fd2,buf,N);
    }

    return 0;
}

使用这两个文件拷贝一个超大的文件,可以发现文件I/O将会比标准I/O慢。

下面深入理解这俩的差别。

内核到磁盘的相互读写有内核自己的一个算法,我们只要把文件内容写到内容或者从内核读取内容,就相当于和磁盘做了数据交换。

而应用程序到内核,需要系统调用。系统调用,用户态到核心态,核心态到用户态这个过程消耗资源会非常大,时间消耗也会非常长。 

文件I/O每一次操作都需要这样的一个过程,我们输入命令:

sudo yum -y install strace

然后输入命令,运行filecopy.c文件编译完成的可执行程序filecopy:

strace ./filecopy 文件1 文件2

发现:

而标准I/O它自带一个缓冲,它先把要写的内容先写到自己的内存,直到写满了它才使用系统调用把内容写到内核中去。

输入命令,运行stdcopy.c编译完成的可执行程序stdcopy:

结果是发现它只执行了一次系统调用。 

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

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

相关文章

TDesign设计系统全方位解析

随着互联网的发展和技术的不断更新和迭代&#xff0c;互联网产品类别的周期越来越短&#xff0c;用户需求也在不断提高。对于生产、设计和研究团队来说&#xff0c;有必要进行高效和持续的设计创新。腾讯“腾讯设计云”的研发帮助企业完成高效协作&#xff0c;提高设计开发效率…

SpringCloud学习:一【详细】

目录 服务架构演变 单体架构 分布式架构 分布式架构需要考虑的问题 微服务 架构比较 微服务技术对比 服务拆分注意事项 案例 服务远程调用 RestTemplate Eureka注册中心 RestTemplate存在的问题 服务调用考虑的问题 Eureka的作用 搭建EurekaServer 服务注册 …

分布式事务——CAP理论 解决分布式事务的思路 Seata组件初识 和 部署

前言 事务(TRANSACTION)是一个不可分割的逻辑单元&#xff0c;包含了一组数据库操作命令&#xff0c;并且把所有的命令作为一个整体向系统提交&#xff0c;要么都执行、要么都不执行。 事务作为系统中必须考虑的问题&#xff0c;无论是在单体项目还是在分布式项目中都需要进行…

Android WMS——概述(一)

Android 中的 WMS 指的是 Window Manager Service(窗口管理服务)。WMS 是 Android 系统中的核心服务,主要分为四大部分,分别是窗口管理,窗口动画,输入系统中转站和 Surface 管理 。负责管理应用程序窗口的创建、移动、调整大小和显示等操作。 一、功能简介 WMS 的职责可…

YOLO目标检测——红外人员数据集【含对应voc、coco和yolo三种格式标签+划分脚本】

实际项目应用&#xff1a;红外热像仪进行安全监控数据集说明&#xff1a;红外人员检测数据集&#xff0c;真实场景的高质量图片数据标签说明&#xff1a;使用lableimg标注软件标注&#xff0c;标注框质量高&#xff0c;含voc(xml)、coco(json)和yolo(txt)三种格式标签&#xff…

华为OD机试 - 德州扑克 - 逻辑分析(Java 2023 B卷 200分)

目录 专栏导读一、题目描述1、判断牌型2、说明 二、输入描述三、输出描述1、输入2、输出3、说明 四、解题思路五、Java算法源码六、效果展示1、输入2、输出3、说明 华为OD机试 2023B卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAV…

自动化学报格式 Overleaf 在线使用 【2023最新教程】

自动化学报格式 Overleaf 在线使用 摘要 2023年10月26日19:28:17&#xff08;云南昆明&#xff09; 今天课程老师要我们期末提交一篇论文&#xff0c;以自动化学报格式提交。因此&#xff0c;去官网发现只有 latex 格式&#xff0c;下载下来发现各种格式不兼容&#xff1b;由于…

postgresql14管理(二)-用户与角色

介绍 查看 SELECT rolname FROM pg_roles;postgres是系统初始化时默认创建的角色&#xff0c;为超级管理员。 \duList of rolesRole name | Attributes | Member of ------------------------------------------------------…

Kafka - 异步/同步发送API

文章目录 异步发送普通异步发送异步发送流程Code 带回调函数的异步发送带回调函数的异步发送流程Code 同步发送API 异步发送 普通异步发送 需求&#xff1a;创建Kafka生产者&#xff0c;采用异步的方式发送到Kafka broker 异步发送流程 Code <!-- https://mvnrepository…

墨西哥专线大型工程设备海运

随着全球经济一体化的不断推进&#xff0c;国际贸易日益繁荣&#xff0c;跨国物流需求不断增长。墨西哥作为拉美地区的经济大国&#xff0c;拥有丰富的资源和庞大的市场&#xff0c;吸引了许多中国企业的投资。然而&#xff0c;由于地理位置的原因&#xff0c;许多大型工程设备…

23种设计模式【创建型模式】详细介绍之【建造者模式】

建造者模式&#xff1a;构建复杂对象的精妙设计 设计模式的分类和应用场景总结建造者模式&#xff1a;构建复杂对象的精妙设计建造者模式的核心思想建造者模式的参与者Java示例&#xff1a;建造者模式 设计模式的分类和应用场景总结 可以查看专栏设计模式&#xff1a;设计模式 …

Anaconda-2023版 下载安装配置(国内镜像+图文详解)

1、Anaconda 下载 1.1 国内镜像下载 Anaconda 是跨平台的&#xff0c;版本众多&#xff0c;小伙伴们按需下载。本文是Win11系统 下载途径一&#xff1a;官方网站 https://www.anaconda.com/download/ 下载途径二&#xff1a;国内清华镜像 https://mirrors.tuna.tsinghua.…

嵌入式基础

本篇文章主要转载自 嵌入式复习&#xff0c;便于自己复习使用。 1 基本概念 嵌入式系统概念&#xff1a;以应用为中心&#xff0c;以计算机为基础&#xff0c;软件、硬件可裁剪&#xff0c;功能、可靠性、成本、体积、功耗严格要求的专用计算机系统&#xff08;国内&#xff0…

Power BI 傻瓜入门 12. 抽取报表

本章内容包含&#xff1a; 设置报表采用各种报表过滤方法探索高级报表功能消化报表发布过程 将您可以使用Power BI创建的每个可视化视为为为数据集提供不同的见解。可视化也可以是独立的&#xff0c;也可以与许多其他可视化相结合。无论哪种方式&#xff0c;可视化的输出都是…

使用Typecho搭建个人博客网站,并内网穿透实现公网访问——“cpolar内网穿透”

使用Typecho搭建个人博客网站&#xff0c;并内网穿透实现公网访问 文章目录 使用Typecho搭建个人博客网站&#xff0c;并内网穿透实现公网访问前言1. 安装环境2. 下载Typecho3. 创建站点4. 访问Typecho5. 安装cpolar6. 远程访问Typecho7. 固定远程访问地址8. 配置typecho 前言 …

linux中断(中断一)

中断是操作系统中至关重要的机制&#xff0c;它能够显著提高系统的响应性能和并发处理能力。   中断是指在 CPU 正常运行期间&#xff0c;由外部或内部事件引起的一种机制。当中断发生时&#xff0c;CPU会停止当前正在执行的程序&#xff0c;并转而执行触发该中断的中断处理程…

drawio特性

drawio的特性 drawio是领先的基于Web技术的草图和图表功能功能的应用。 保证数据的安全 集成了各种不同的平台&#xff0c;和提供了在线的免费编辑器&#xff0c;可以使用app.diagrams.net来方案&#xff0c;drawio本身不会存储用户的数据。 随着互联网时代的发展&#xff0…

死锁是什么?如何避免?如何排查?为什么这样排查 详细总结

1.死锁是什么 多个线程访问资源 线程加锁不当 会造成死锁。导致所有线程被阻塞&#xff0c;且无法解开 2.死锁的产生原因 1.加锁后忘记解锁 2.重复加锁&#xff0c;造成死锁 3.B锁内部调用函数A &#xff0c;A运行是又加锁 导致A,B均无法运行 3.如何避免死锁 多检查…

【vector题解】杨辉三角 | 删除有序数组中的重复项 | 只出现一次的数字Ⅱ

杨辉三角 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 给定一个非负整数 numRows&#xff0c;生成「杨辉三角」的前 numRows 行。 在「杨辉三角」中&#xff0c;每个数是它左上方和右上方的数的和。 示例 1: 输入: numRows 5 输出: [[1],[1,1…

操作系统【OS】死锁

常考点 系统资源不足不是系统产生死锁的原因&#xff0c;资源不足只会对进程造成“饥饿”【详见王道操作系统书P153第4题】 A&#xff1a;资源不足和资源分配不足还是有区别的啦~ 死锁是什么&#xff1f; 死锁是多个进程因为竞争资源而造成的一种互相等待 为什么会出现死锁&…