博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
《C程序设计语言》笔记 (八) UNIX系统接口
阅读量:4465 次
发布时间:2019-06-08

本文共 3324 字,大约阅读时间需要 11 分钟。

8.1 文件描述符

UNIX操作系统通过一系列的系统调用提供服务,这些系统调用实际上就是操作系统内的函数ANSI C标准函数库是以UNIX系统为基础建立起来的在UNIX系统中所有的外围设备都被看作是文件系统中的文件,因此,所有的输入输出都要通过文件读写完成也就是说,通过一个单一的接口就可以处理外围设备和程序之间的所有通信在读写文件之前,必须先将这个意图通知系统,该过程称为打开文件如果是写写一个文件,则可能需要先创建该文件操作系统想程序返回一个小的非负整数,该整数称为文件描述符。任何时候对文件的输入输出都是通过文件描述符标识文件,而不是通过文件名标识文件系统负责维护已打开文件的所有信息,用户程序只能通过文件描述符引用文件因为大多数的输入输出都是通过键盘和显示器来实现的为了方便起见,UNIX对此做了特别的安排当命令解释程序运行一个程序的时候,它将打开3个文件对应的文件描述符分别是012 依次标识标准输入 标准输出 标准错误

  

8.2 低级IO --read和write

 

输入输出是通过read和write系统调用实现的在C语言中,可以通过函数read和write访问这两个系统调用read(int fd,char *buf,int n);write(int fd,char *buf,int n);第一个参数是文件描述符第二个参数是程序中存放读写的数据的字符数组第三个参数是要传输的字节数没个调用返回实际传输的字节数在读文件时,函数的返回值可能会小于请求的字节数如果返回值为0,则标识已到达文件结尾如果返回-1则表示发生了某种错误在写文件时返回值是实际写入的字节数如果返回值与写入的字节数不相等,则说明发生了错误在一次调用中,读写的数据可以为任意大小最常用的值为1,即每次读写1字节(无缓冲)或是类似于1024或4096这样的与外围设备的物理块大小相应的值用更大的值调用该函数可以获得更高的效率,因为系统调用的次数减少了#include "syscalls.h"main(){   char buf[BUFSIZ];   int n;   while((n = read(0,buf,BUFSIZ)) > 0)      write(1,buf,BUFSIZ);   return 0;}系统调用的函数原型集中放在一个syscalls.h中参数BUFSIZ也已经包含中头文件中对应所使用的操作系统来说,该值是一个较合适的数值如果文件大小不是BUFSIZ的倍数,则对read的某次调用会返回一个较小的字节数//getchar实现int getchar(void){   char c;   return (read(0,&c,1)==1)?(unsigned char) c : EOF;}其中c必须是一个char类型的变量,因为read函数需要一个字符指针类型的参数在返回语句中将c转换为unsigned char类型可以消除符号扩展问题如果要在包含头文件
的情况下编译getchar函数就必须用#undef预处理指令取消getchar的宏定义因为在头文件中,getchar是以宏方式实现的

  

8.3 open creat close 和unlink

除了默认的标准输入 标准输出和标准错误文件外其他文件都必须在读写前显式打开系统调用open和creat用于实现该功能open和fopen很相似,不同的是 open非常一个文件描述符 int类型的数值fopen返回一个文件指针#include 
int fd;fd = open(char *name,int flags,int perms);参数name文件名flags是一个int类型的值,说明文件打开方式 包括 O_RDONLY 只读 O_WRONLY 只写 O_RDWR 读写目前 open 参数perms的值始终为0;如果打开的文件不存在则将导致错误可以使用creat系统调用创建新文件或覆盖已有的文件int fd;fd = creat(char *name,int perms);如果创建成功返回文件描述符 否则返回-1如果此文件已存在,清空原来数据使用creat创建一个已经存在的文件不会导致错误如果要创建的文件不存在,以参数perms指定的权限创建文件每个文件对应一个9比特的权限信息所有者所有者组其他成员一个程序同时打开的文件数是有限制的(通常为20)如果一个程序需要同时处理许多文件,那么他必须重用文件描述符函数close用了断开文件描述符和已打开文件直接的连接,并释放此文件描述符close函数和标准库中的fclose函数想对应,但它不需要清洗(flush)缓冲区如果程序通过exit函数退出或从主程序中返回,所有打开的文件将被关闭函数unlink将文件从文件系统中删除,它对应标准库函数remove

  

8.4 随机访问 lseek

输入输出通常是顺序进行的每次调用read和write进行读写的位置紧跟在前一个操作的位置后但是,有时需要以任意的顺序访问文件,系统调用lseek可以在文件中任意移动位置而不实际读写任何数据long lseek(int fd,long offset,int orign);将文件描述符fd的当前位置设置为offsetoffset是相对于origin指定的位置而言随后进行的读写操作将从此位置开始使用lseek系统调用时,可以将文件视为一个大数组,其代价是访问速度慢一些标准库函数fseek和系统调用lseek类似不同的是,前者的第一个参数是FILE *类型且发生错误时返回一个非0值

  

8.5 实例 --  fopen和getc函数的实现

标准库中的文件不是通过文件描述符描述的,而是使用文件指针描述的文件指针是一个指向包含文件各种信息的结构的指针包含如下信息:一个指向缓冲区的指针,通过它可以一次读入文件的一大块内容一个记录缓冲区中剩余的字符数的计数器一个指向缓冲区下一个字符的指针文件描述符描述读写模式的标志描述错误状态的标志描述文件的数据结构包含在
中只供标准库中其他函数使用的名字以下划线开始,因此一般不会和用户程序中的名字冲突

  

8.6 实例 -- 目录列表

在UNIX中的目录就是一种文件ls只需读取此文件就可以获得所有的文件名但是如果需要获取文件的其他信息,就需要系统调用

  

8.7 实例 -- 存储分配程序

malloc在必要是调用系统以获取更多的存储空间malloc并不是从一个在编译时就确定的固定大小的数组中分配存储空间而是在需要的时候想操作系统申请空间因为程序中的某些地方可能不通过malloc申请空间所以malloc管理的空间不一定是连续的这样空闲存储空间以空闲块链表的方式组织每个块包含一个长度 一个指向下一块的指针及一个指向自身存储空间的指针当有申请请求时,malloc将扫描空闲块链表,直到找到一个足够大的块为止该算法称为 "首次适应"与之对应的算法是"最佳适应"如果块恰好与请求的大小符合将它从链表中移走并返回给用户如果块太大,则将它分成两部分:大小合适的返回给用户,剩下的部分留在空闲链表中如果找不到足够大的块,则想操作系统申请一个大块并加入到空闲链表中释放过程也是首先搜索空闲链表以找到可以插入被释放块的合适位置如果与被释放块相邻的任意一边是空闲,则将两块合并成一个大块由malloc返回的存储空间满足将要保存的对象的对齐要求虽然机器类型各异,但是每个特定的机器都有一个最受限的类型如果最受限的类型可以存储在某个特定的地址中则其他所以的类型也可以存放在此地址中向系统申请存储空间是一个开销很大的操作我们不希望每次malloc执行该操作UNIX系统调用sbrk(n)返回一个指针,该指针指向n个字节的存储空间如果没有空闲空间,sbrk返回-1

  

 

转载于:https://www.cnblogs.com/dafume/p/7813008.html

你可能感兴趣的文章
OO第四次博客作业!
查看>>
HDU 吉哥系列故事——完美队形II 騰訊馬拉松初賽第二輪D題
查看>>
[转]SQL Server 性能调优(io)
查看>>
设计模式学习-每日一记(6.原型模式)
查看>>
不已0开头的数字正则
查看>>
HTML撑起浮动子元素得父元素高度
查看>>
LeetCode--018--四数之和(java)
查看>>
Redis消息队列
查看>>
电商网站架构设计
查看>>
http://jingyan.baidu.com/article/4dc40848e7b69bc8d946f127.html
查看>>
WCF netTcp配置
查看>>
数据类型转换
查看>>
Nodejs学习笔记(2) 阻塞/非阻塞实例 与 Nodejs事件
查看>>
什么是FreeMaker
查看>>
设计模式学习笔记(总结篇:模式分类)
查看>>
TCP的三次握手/建立连接
查看>>
Python 教程阅读笔记(一):使用解释器
查看>>
运算符重载
查看>>
SDWebImage 新版接口使用方法
查看>>
DataTable导出为word,excel,html,csv,pdf,.txt
查看>>