读apue的部分笔记(一)

一、UNIX 文件 I/O
一提到操作文件,就离不开文件描述符,每一个新建的或打开的文件都会有一个
用整数唯一标示的的文件描述符,creat和open都会返回一个文件描述符,其它
操作文件的系统调用都会用这个的文件描述符来操作指定的文件。
UNIX 中什么都是文件,标准输入输出和标准错误都是文件,所以它们都有文件
描述符,标准输入的文件描述符是0,标准输出的文件描述符是1,标准输出的
的描述符是2。文件的偏移量都是从文件开头算起的,一般默认情况下,打开的
文件的偏移量是0。文件的读写都是从当前的偏移量开始的,当然了,文件属性
中肯定会有偏移量这一项的,每完成一次读或写操作都会更新文件的偏移量。
UNIX的文件共享:内核用三个结构体来实现三层分离,这样可以灵活地实现共享。
见图:


1、操作文件的五个函数(详见 man 2 函数名)

1.1 open

1.2 read

读到文件的结尾处read会返回0。
1.3 write

1.4 lseek
用来显式地设置文件的偏移量。用这个系统调用还可以产生文件孔洞。

1.5 close

二、UNIX 文件的访问权限(主要围绕stat系统调用展开的)
在UNIX 中,每个文件都有三种权限,可读、可写、可执行。文件的用户也分
三种,文件所有者(owner)、文件所属组(group)、其他(other)。
通过文件名打开某个文件时,首先要对包含这个文件的文件夹有执行的权力,因为文件夹
也是文件。说到这里,unix中的文件有常规文件、目录文件、块文件、字符文件、
有名管道文件(fifo)、socket。
目录文件的读权限和执行权限是不同的。读权限允许读出目录文件的内容,也即这个文件
夹中所包含的文件名列表;执行权限是当这个目录是一个路径中的一部分时,可以通过这
个文件夹,进而进入这个文件夹。如果一个文件夹没有执行的权限,这个文件夹里面的可
执行文件是不会被执行的,也就是通过这个路径想执行某个可执行文件是做不到的。
当新建一个文件时,其stat结构体中的用户id项会被赋成创建这个文件的进程的用户的id,
其组id根据系统不同可能是文件所在的目录的组id也可能是进程的组id。
符号连接也是文件,符号连接文件的大小就是其文件名的字节数。
读UNIX书时会遇到core file这个说法,其意思是在内存中的文件,我感觉这主要是相对
外存硬盘说的。
硬链接本质是在要链接的目录中添加一个普通文件项,只不过这个文件项中的指向文件i-node
的指针(暂且叫指针,其实是数字,即所指的i-node号)是指向被链接文件的i-node。
实现硬链接的系统调用是link。
读目录的两个系统调用是opendir和readdir,利用这两个函数可以实现一个简单的ls。
一个进程的当前工作目录是这个进程的一个属性。
获得进程当前工作目录的函数是getcwd,全称是get current working directory。

三、标准C的I/O库
丹尼斯在75年写的C标准库,30多年过去了,其标准库基本上没啥变化,这充分说明了底层
东西的基础性,也说明了当年老前辈的设计是多么的出色。
在这里有必要说明一个疑问,既然系统调用可以直接操作文件,而标准库函数还要调用系统
调用来操作文件,那问什么还要有库函数,或者说库函数和系统调用的区别是什么?
apue中是这样说的,我也不翻译直接原文粘贴:The standard I/O library 
handles such details as buffer allocation and performing I/O in 
optimal-sized chunks, obviating our need to worry about using the 
correct block size . This makes the library easy to use, but at 
the same time introduces another set of problems if we're not 
cognizant of what's going on. 
补充一点我的理解,库函数主要是给应用程序员用的,所以要简单好用,不必考虑太多底层
细节,比如apue中提到的,read和write中的buffer的大小是多时时读写的效率才最高,
这个一般对应用程序员来说是困难的也是没有必要知道的,所以就需要库函数;另外,一个
人发明一种语言,没有库函数只有编译器,这种语言是不完整的,库函数是这个语言的接口,
没有了库函数就会给无数程序员带来很多不必要的麻烦,估计这也是写库函数人的意义所在吧!
不同的os有不同的系统调用,即不同的接口,但是一种语言的库函数在不同的操作系统上是
一样的,所以使得语言具有了可移植性,因此说C语言是可移植的。越是底层的接口给程序员
提供的灵活性也越大越直接,可以最大限度地操作硬件,但是也越是难以控制,一般只有资
深的系统程序员才直接调用系统调用来完成库函数的功能。
在系统调用操作文件时,中心是文件描述符;而到了库函数操作文件时中心是stream,用库
函数打开或创建一个文件时就把一个stream与之关联上了。
stream是有方向的,它的方向表明了它是单字节stream还是多字节stream。
当我们打开一个stream时,fopen会返回一个指向FILE 对象的指针,并且会有一个文件
描述符关联到这个stream,用fileno函数可以获取这个文件描述符。这个对象包含了用
标准库操作文件的所有信息,比如文件描述符,缓冲区,缓冲区的大小,当前缓冲区中有多
少字符等等。
一个进程会有三个预定义的stream与之关联,标准输入、标准输出、标准错误。引用这三个
文件的指针分别为,stdin,stdout,stderr。
操作文件的系统调用是无缓冲的,标准I/O库提供缓冲的目的是使调用read和write的次数
最少。I/O缓冲有三种,全缓冲、行缓冲、无缓冲,库函数的缓冲区也是可以设置的,
man setbuf。
getc,fgetc,getchar这三个函数都是每次读入一个字符,详解用man
printf的返回值是其输出的字符数。
gnu的I/O库是开源的,意思是感兴趣的话可以看看库函数是咋实现的。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值