首页 > 其他分享 >文件IO学习【三】

文件IO学习【三】

时间:2024-05-11 08:57:44浏览次数:29  
标签:文件 函数 系统 学习 内核 IO Linux

目录

系统IO接口说明

概念解释

由于Linux系统下“一切皆文件”,也就是Linux系统下的数据和程序都是以文件的形式存储的,所以Linux内核会提供一组操作文件的函数接口,这组函数接口也被称为系统IO,同时为了满足用户访问文件的需求以及提高用户程序的可移植性,标准库也提供了一组操作文件的函数接口,这组函数接口也被称为标准IO,只不过标准库提供的标准IO函数都是遵循ANSI C标准设计出来,是为了方便用户在不同的操作系统下可以调用通用的函数来实现对文件的读写访问,但其实标准IO也是基于内核提供的系统IO设计出来的。

标准IO和系统IO的区别

  • 标准IO提供了输入输出缓冲区,而系统IO不具备输入输出缓冲区。

    该特性使得标准IO避免了频繁的系统调用,且不用人为关心缓冲区大小的选择,整体上提高了I/O的效率;而系统IO则无法高效的处理数据。原因是系统调用与普通函数调用相比通常需要花费更多的时间,因为系统调用的过程中内核要执行一系列的操作:首先内核需要捕获调用,然后再检查系统调用传递的参数的有效性,最后在用户空间和内核空间之间传输数据。

  • 系统IO能够针对特定类型文件(链接文件、套接字文件等)进行访问,一般适合访问数据需要实时刷新的硬件设备(LCD、触摸屏......);而标准IO做不到这点,标准IO一般适合访问普通文件(规则文件)

    简单理解:

    标准I/O可以看成是在系统I/O的基础上封装了缓冲机制。这样可以先读写缓冲区,必要时再访问实际文件,从而减少了系统调用的次数,提高访问效率。例如:

    fwrite() --> a.txt -->fwrite(buf,1,1,fp); --> write() --> 100个字节要写--> 调用100次write() -->慢

    fwrite() --> a.txt -->fwrite(buf,1,100,fp); -->write() -->100个字节要写-->调用001次write() -->快

  • *标准IO利用链表管理打开文件,所以返回值为FILE 而系统IO利用顺序表管理打开文件,所以返回值是一个文件描述符(非负整数),意为顺序表数组的下标。

    常用系统IO函数介绍

    打开文件

    Linux内核提供了用于打开文件的open函数,由于该函数属于系统IO函数,所以在C99标准中是查询不到的,可以在Linux系统的man手册的第二个章节中找到系统IO函数的描述。

image

image

image

通过man手册可知,open()的第一个参数为要打开的文件的路径,第二个参数flags为打开文件的部分权限【只读、只写,可读可写】,且flags必须在这三种权限中选择一个填写。但是,设计者考虑到打开文件情况的多样性,还设定了多个不同的权限函数,使用时需要利用位或(bitwise-or)将多个模式连接,例如: O_RDONLY | O_CREAT

可以看到,open函数的第三个参数mode只有在open函数的第二个参数flags使用O_CREAT或者O_TMPFILE才会使用,也就是说,打开一个已经存在的文件使用第一个版本的open函数即可,第二个版本的open函数的mode参数是指利用open函数创建新文件时给新创建的文件一个指定权限,被创建的文件的权限其实就是Linux系统下文件的权限,可以分为三种:

image

一般在Linux系统下可以直接使用shell命令来修改文件的权限,比如指令chmod 0777 xxx.txt就是给该文档一个最高权限。注意:mode参数应该采用八进制。

image

注意:

​ 由于此时mode参数采用八进制表示,所以在使用时应该加上八进制标识符0.

image

通过man手册可以知道,如果文件打开成功,则open函数返回一个文件描述符,这个文件描述符是一个非负整数,并且这个非负整数是当前进程中未被分配的文件描述符中最小的。如果文件打开失败,则open函数的返回值是-1,并且错误原因采用错误码的方式进行存储。

思考:

​ 请问这个open函数的文件描述符有什么作用?这个返回值对应的数字范围是多少???

回答:

​ open函数的返回值可以理解为是被打开文件的代号,内核并不是以被打开文件的路径和名称来管理文件,而是在调用open函数的时候会从未分配的文件描述符中找到一个最小的提供给被打开的文件。在对文件进行读写(R/W)访问时同样是通过这个文件描述符实现。所以需要再打开文件时设置一个整型变量用于存储open()返回的文件描述符

  • 文件描述符本质就是一个非负整数,从内核源码角度分析,这个整数实际上是内核中的一个称为 fd_array 的数组下标。

image

打开文件时,内核产生一个指向 file{} 的指针,并将该指针放入一个位于 file_struct{} 中的数组 fd_array[] 中,而该指针所在数组的下标,就被 open() 返回给用户,所以内核把这个数组下标称为文件描述符。

文件描述符从0开始分配,每打开一个文件,就产生一个新的文件描述符。当然,用户可以重复打开同一个文件,每次打开文件都会使内核产生新的结构体,并得到不同的文件描述符。

注意:

虽然文件描述符是从0开始分配,但由于我们打开文件一般是做读写操作,所以在打开文件之前,系统会打开三个标准文件【stdin、stdout、stderr】。因此,打开文件的描述符最小应该是从 3 开始。

思考:

​ 可以知道一个程序中能打开的文件的数量最大为1024个,请问是否可以修改这个值

回答:

​ 可以通过Linux系统提供了一个查看和修改系统资源的shell命令: ulimit -a 来打印当前系统所有资料的阈值

image

注意:

​ 上图所示的数值,均是由Linux内核设置,若是想要对其进行修改操作,则需要写明修改项的参数,如想要对打开文件的数量进行修改:ulimit -n xxx(想要修改的数量)

​ 且这样的修改本次有效,若是想要一直有效,则需要将其写入Linux内核代码中。

关闭文件

Linux内核提供了用于关闭文件的close函数,由于该函数属于系统IO函数,所以在C99标准中是查询不到的,可以在Linux系统的man手册的第二个章节中找到系统IO函数的描述。

image

注意:

close函数可以对同一个文件反复调用,并且不会出错,因为open函数没有申请堆内存,但是多次调用close函数关闭同一个文件的动作是没有意义

文件读取

Linux内核提供了用于读取文件的read函数,由于该函数属于系统IO函数,所以在C99标准中是查询不到的,可以在Linux系统的man手册的第二个章节中找到系统IO函数的描述。

image

由man手册可知,read()需要三个参数,分别是读取文件的路径、存放读取数据的自定义缓冲区和需要读取的数量。且与fread()不同的是,read()能够读到最多count个数据,而不是count - 1个;

read()的返回值是读取字节数量,如果返回值是0,说明读取到文件末尾,如果返回值是-1,说明读取出错

文件写入

Linux内核提供了用于写入文件的write函数,由于该函数属于系统IO函数,所以在C99标准中是查询不到的,可以在Linux系统的man手册的第二个章节中找到系统IO函数的描述。

image

位置偏移

Linux内核提供了用于设置文件位移的lseek函数,由于该函数属于系统IO函数,所以在C99标准中是查询不到的,可以在Linux系统的man手册的第二个章节中找到系统IO函数的描述。

image

注意:

​ lseek()与fseek()使用规则一致,但是,lseek()会将文件指示器相较于文件开头的偏移量,以字节为单位返回。而fseek()需要借助ftell()才能做到。

标签:文件,函数,系统,学习,内核,IO,Linux
From: https://www.cnblogs.com/fly-home/p/18185678

相关文章

  • SpringBoot整合Mybatis时mapper文件和xml文件的位置
    xml文件放在resources下看下我的项目目录2.由于放在resurces下就无法扫描到xml文件,所以就需要在配置文件配置--mapper文件位置mybatis.mapper-locations=classpath:mapper/*.xml或mybatis.mapper-locations=classpath:/mapper/*.xmlxml和mapper文件放在一起我的项目......
  • 数据结构学习01--栈
    栈栈的特性栈的基本结构我们可以把栈想象成一个装有弹珠的瓶子,先放进去的弹珠在瓶子底部,每次只能将顶部的弹珠倒出。栈的特点由图可以很好的知道后进先出栈的实际应用简单栈栈的概念非常简单,但把这个数据结构运用得当是需要充分理解的。应用1:判断字符串是否合法特殊情......
  • 【学习笔记】Python 装饰器
    装饰器是Python中一种非常强大的语法特性,它允许你在不改变函数代码的情况下,动态地增加功能。装饰器本质上是一个函数,它接受一个函数作为参数,并返回一个新的函数。下面是Python装饰器的基本语法:defdecorator_function(original_function):defwrapper_function(*args,*......
  • 使用stable diffusion设计logo的提示词
    使用stablediffusion设计logo的提示词StableDiffusion是一种基于图像处理和机器学习的算法,可以用于生成各种类型的图像,包括Logo设计。本文将介绍如何使用StableDiffusion来设计Logo,并提供一些提示词以帮助读者更好地理解和应用这种技术。1.了解StableDiffusion的基本原理在......
  • Nginx 做静态文件服务器,多系统互相访问文件权限校验配置
    问题背景:接到个需求,客户有两个系统要互相访问文件,文件服务器是通过nginx搭建的,原来的访问地址如下:http://abc.cn/file/fa1a8d99a47b4c8c9d59152728af9930.docx客户说这个不安全,任何人都能访问,一定要做权限校验接到这个需求我觉得安全隐患不是很大,因为文件名是随机的,nginx也不支......
  • 【golang】go语言学习需要注意的点
     (学习可参考菜鸟教程:https://www.runoob.com/go/go-basic-syntax.html) 1.Go编译生成的exe程序在后台运行(不闪过console窗口)gobuild-ldflags"-s-w-H=windowsgui"-s省略符号表和调试信息-wOmittheDWARFsymboltable省略DWARF符号表-Hwindowsgui不打印信......
  • Django 静态文件管理与部署指南
    title:Django静态文件管理与部署指南date:2024/5/1017:38:36updated:2024/5/1017:38:36categories:后端开发tags:WebOptCDN加速DjangoCompressWebpackStaticDeployCICD-ToolsSecStatic第一章:介绍Django静态文件的概念和重要性在Web开发中,静态文件......
  • sqlSession相关的作用域和生命周期
    生命周期和作用域是十分重要的,错误的使用会导致非常严重的并发问题。Mybatis的执行流程详细讲解SqlSessionFactoryBuilder:一旦创建了SqlSessionFactory,就不需要它了,比较适合在局部变量中创建。SqlSessionFactory:相当于数据库的连接池;SqlSessionFactory一旦被创建就应......
  • 爆爽,英语小白怒刷 50 课!像玩游戏一样学习英语~
    ###重点!!!(先看这)1.清楚自己学英语的`目的`,先搞清楚目标,再行动2.自身现在最需要的东西:`词汇量`?`口语`?还是`阅读能力`?3.找对应的书籍,学习资料4.往`兴趣靠拢`:网上有大量的推荐美剧学习、小说学习,不要被他们迷了眼,适合他们的不一定适合你,找到适合的你才能长期坚持下......
  • 开源相机管理库Aravis例程学习(七)——chunk-parser
    目录简介例程代码函数说明arv_camera_create_chunk_parserarv_camera_set_chunksarv_chunk_parser_get_integer_value简介本文针对官方例程中的:05-chunk-parser做简单的讲解。并介绍其中调用的arv_camera_create_chunk_parser,arv_camera_set_chunks,arv_chunk_parser_get_integer......