CSAPP--Chap10 系统级I/O

输入/输出(I/O) : 是指主存外部设备(如磁盘,终端,网络)之间拷贝数据过程。

  • 高级别I/O函数

    • scanfprintf
    • <<>>
    • 使用系统级I/O函数实现
  • 系统级I/O函数。   

 

10.1 Unix I/O

  • 一个Unix 文件就是一个m个字节的序列:

    • 所有I/O设备都被模型化为文件
    • 而所有的输入和输出都被当做相应文件读和写
  • 设备优雅地映射成文件,允许Unix内核引出一个简单低级应用接口。叫做Unix I/O

    • 使得所有的输入输出都能以一种统一且一致的方式来执行。

      • 打开文件: 应用程序要求内核打开文件

        • 内核返回一个小的非负整数,叫做描述符

          • 等于内核分配一个文件名,来标示当前的文件。
          • 内核记录有关这个打开文件的所有信息。应用程序只需要记住标示符。
        • Unix外壳创建进程时都有三个打开的文件

          • 标准输入(标示符0)
          • 标准输出(标示符1)
          • 标准错误(标示符2)
          • 头文件<unistd.h>定义了常量代替显式的描述符值
            • STDIN_FILENO
            • STDOUT_FILENO
            • STDERR_FILENO
      • 改变当前文件的位置(非文件目录)

        • 对于每个打开的文件,内核保持一个文件位置k

          • 初始为0
          • 文件位置即是从文件开头起始的字节偏移量
        • 执行lseek操作,显式地设置文件位置

      • 读写文件

        • 一个读操作就是从文件拷贝n个字节到存储器,然后将k增加到k+n

          • 给定一个大小为m字节的文件,当k>=m执行读操作会触发一个称 为end-of-file(EOF)的条件。
            • 应用程序能检测到这个条件(或者说信号?)
            • 文件结尾并没有这样的符号。
        • 写操作就是从存储器拷贝n个字节到一个文件,从当前文件位置k开始,然后更新k

      • 关闭文件 :当应用程序完成了文件的访问,通知内核关闭文件。

        • 响应

          • 内核释放文件打开时创建的数据结构。
          • 描述符恢复到可用的描述符池中。
        • 无论一个进程因为何种原因被关闭,内核会关闭所有它打开的文件。

10.2 打开和关闭文件

进程是通过调用 open函数来打开一个已存在的文件或者创建一个新文件的

#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>

int open(char *filename,int flags,mode_t mode);

 //返回:若成功则为新文件描述符,若出错为-1

open函数将filename转换为一个文件描述符,并且返回描述符数字。

  • 返回的描述符总是在进程当前没有打开的最小描述符

  • flags参数指明了进程打算如何访问这个文件:

    • 可是以一个多个掩码的或。(拿二进制思想思考)
    • O_RDONLY: 只读
    • O_WRONLY: 只写
      • O_CREAT : 如果文件不存在,就创建一个截断的(truncated)(空)文件。
      • O_TRUNC : 如果文件已存在,就截断它(长度被截为0,属性不变)
      • O_APPEND: 在每次写操作前,设置文件位置到文件的结尾
    • O_RDWR: 可读可写

      例子代码
      
      //已只读模式打开一个文件
      fd = Open("foo.txt",O_RDONLY,0);
      //打开一个已存在的文件,并在后面面添加一个数据
      fd = Open("foo.txt",O_WRONLY|O_APPEND,0);
      
  • mode参数指定了新文件的访问权限位。

    • 每个进程都有umask

      • 权限掩码,或 权限屏蔽字
      • 所有被设置的权限都要减去这个权限掩码才是实际权限。
        • 777-022=755 或者是 777&~022
      • 通过umask()函数设置
    • mode并不是实际权限

      • 文件的权限位被设置为mode & ~umask,也可以表示两者相减。
    • 例子

      #define DEF_MODE S_IRUSR|S_IWUSER|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH
      //所有人都能读和写
      #define DEF_UMASK S_IWGRP|S_IWOTH //屏蔽了用户组的写和其他人的写
      
      umask(DEF_UMASK);
      fd=oepn("foo.txt",O_CREAT|O_TRUNC|O_WRONLY,DEF_MODE);
      //创建了一个新文件,文件的拥有者有读写权利,其他人只有读权限。(屏蔽了用户组的写和其他人的写)
      

       

 

close函数关闭一个打开的文件

#include <unistd.h>

int close(int fd);

                //返回: 若成功则为0,若出错则为-1

关闭一个已关闭的描述符会出错。

10.3 读和写文件

调用readwrite完成输入输出

#include <unistd.h>

ssize_t read(int fd,void *buf,size_t n);
//read函数从描述符fd的当前文件位置拷贝最多n个字节到存储器buf

                    返回:若成功则为读的字节数,若EOF则为0,若出错为 -1.
ssize_t write(int fd,const void *buf,size_t n)
//write函数从存储器位置buf拷贝至多n个字节到描述符fd的当前文件位置

                    返回:若成功则为写的字节数,若出错则为-1

展示了一个程序使用readwrite调用一次一个字节的从标准输入拷贝到标准输出

 

通过调用lseek函数,应用程序能够显示地修改当前文件的位置

ssize_t 和 size_t 有什么区别

  • size_t:被定义为unsigned int
  • ssize_t:被定义为int
    • 为了出错的时候,返回-1.
    • 有趣的是,因为这个-1,使得read的最大值减小了一半。

在某些情况,readwrite传送的字节比应用程序要求的要少,有以下原因。
这样的情况返回的值叫做不足值

  • 读时遇到EOF。
  • 从终端读文本行(stdinSTDIN_FILENO)

    • 不足值等于文本行的大小。
  • 读和写网络套接字(socket)

    • 内部缓冲约束和较长的网络延迟会引起readwrite返回不足值。
    • 你向创建健壮的诸如Web服务器这样的网络应用,就必须反复调用readwrite处理不足值,知道所有需要的字节传送完毕。

一般的磁盘文件除了EOF外,一般不会遇到不足值的问题。

 

10.6 共享文件

内核有三个相关的数据结构来表示打开的文件:

  • 描述符表(descriptor table):

    • 每个进程都有它独立描述符表
    • 它的表项是由进程打开的文件描述符来索引的。
    • 每个打开的描述符表项指向文件表的一个表项。
  • 文件表:打开文件的集合是由一张文件表表示的。

    • 所有的进程共享这张表。
    • 每个文件表项的部分组成是
      • 当前的文件位置
      • 引用计数(reference count):即当前指向该表项的描述符项数。
        • 关闭一个描述符会减少相应文件表表项中的引用计数
        • 引用计数变为0。内核会删除这个文件表表项。
      • 以及一个指向v-node表中对应表项的指针。
  • v-node

    • 所有的进程共享这张表。
    • 每个表项包含stat结构的大多数信息。
      • st_mode
      • st_size

打开文件有三种可能的情形:

最常见的类型

  • 就是打开两个不同的文件,且文件磁盘位置也不一样。
  • 没有进行共享.

 

共享情况1

 

  • 多个描述符也可以通过引用不同的文件表表项来引用同一个文件
  • 内容相同,文件位置不同(指向的磁盘位置是同一块)
  • 例子
    • 如果以同一个filename调用open两次,就会出现这种情况。
    • 每个描述符都有它自己的文件位置,所以对不同描述符的读操作可以从文件的不同位置获取数据。

子父进程共享情况

我们也能理解父子进程如何共享文件。

  • 调用fork后,子进程有一个父进程描述符表副本。
  • 父子进程共享相同的打开文件表

    • 共享相同的文件位置
  • 一个很重要的结果

    • 在内核删除对应文件表表项之前,父子进程必须都关闭它们的描述符
    • 不要以为父进程close(fd 1)就好了。
      • 子进程也要close(fd 1)

10.7 I/O 重定向

Unix外壳提供了I/O重定向功能,允许用户将磁盘文件和标准输入输出联系起来。

  • 例如

    unix> ls > foo.txt
    
    • 使得shell加载和执行ls程序,将标准输出重定向到磁盘文件foo.txt
  • 一个Web程序代表客户端允许CGI程序时,也执行一种相似类型的重定向。


I/O重定向如何工作?

  • 使用dup2函数

    #include<unistd.h>
    
    int dup2(int oldfd,int newfd);
    
                返回:若成功则为非负的描述符,若出错则为-1
    
    • dup2函数拷贝描述符表表项 oldfd 到描述符表表项 newfd ,覆盖newfd
      • 如果newfd已经打开,dup2会在拷贝oldfd之前关闭newfd

 

 

10.8 标准I/O

ANSIC定义了一组高级输入输出函数,称为标准I/O库。

  • 这个库(libc)提供了

    • 打开和关闭文件的函数(fopenfclose)
    • 读和写字节(freadfwrite)
    • 读和写字符串的函数(fgetsfputs)
    • 以及复杂的格式化I/O函数 (scanfprintf)
  • 标准I/O库将一个打开的文件模型化为一个

    • 对于程序员来说,一个就是一个指向FILE类型的结构的指针。
    • 每个ANSI C程序开始时都有三个打开的

      • stdin 标准输入
      • stdout 标准输出
      • stdout 标准错误

        #include<stdio.h>
        extern FILE *stdin;
        extern FILE *stdout;
        extern FILE *stderr;
        
  • 类型为FILE的流是对文件描述符流缓冲区的抽象。

    • 流缓冲区的目的和RIO读缓冲区的目的一样
      • 就是使开销较高的Unix I/O系统调用的数量尽可能的少。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
目标检测(Object Detection)是计算机视觉领域的一个核心问题,其主要任务是找出图像中所有感兴趣的目标(物体),并确定它们的类别和位置。以下是对目标检测的详细阐述: 一、基本概念 目标检测的任务是解决“在哪里?是什么?”的问题,即定位出图像中目标的位置并识别出目标的类别。由于各类物体具有不同的外观、形状和姿态,加上成像时光照、遮挡等因素的干扰,目标检测一直是计算机视觉领域最具挑战性的任务之一。 二、核心问题 目标检测涉及以下几个核心问题: 分类问题:判断图像中的目标属于哪个类别。 定位问题:确定目标在图像中的具体位置。 大小问题:目标可能具有不同的大小。 形状问题:目标可能具有不同的形状。 三、算法分类 基于深度学习的目标检测算法主要分为两大类: Two-stage算法:先进行区域生成(Region Proposal),生成有可能包含待检物体的预选框(Region Proposal),再通过卷积神经网络进行样本分类。常见的Two-stage算法包括R-CNN、Fast R-CNN、Faster R-CNN等。 One-stage算法:不用生成区域提议,直接在网络中提取特征来预测物体分类和位置。常见的One-stage算法包括YOLO系列(YOLOv1、YOLOv2、YOLOv3、YOLOv4、YOLOv5等)、SSD和RetinaNet等。 四、算法原理 以YOLO系列为例,YOLO将目标检测视为回归问题,将输入图像一次性划分为多个区域,直接在输出层预测边界框和类别概率。YOLO采用卷积网络来提取特征,使用全连接层来得到预测值。其网络结构通常包含多个卷积层和全连接层,通过卷积层提取图像特征,通过全连接层输出预测结果。 五、应用领域 目标检测技术已经广泛应用于各个领域,为人们的生活带来了极大的便利。以下是一些主要的应用领域: 安全监控:在商场、银行
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值