《Linux程序设计》复习笔记1
文件操作
大多数情况下,只需知道5个基本的函数--open,close,read,write,ioctl(将控制信息传递给设备驱动程序)。在Linux中,一切都是文件。文件除了本身包含的文件内容以外,它还会有一个名字和一些属性,也就是文件的管理信息,包括文件的创建/修改日期和文件的访问权限等。这些属性都被保存在文件的inode节点中,它是文件系统中的一个特殊的数据块,它同时还包含文件的长度和文件在磁盘上的存放位置。系统使用的是文件的inode编号,目录结构为文件起个名字仅仅是为了人们使用方便。
可以通过ln命令在不同的目录中创建指向同一个文件的链接,删除一个文件的时候,实质上市删除了该文件对应的目录项,同时指向该文件的链接数减去1。该文件中的数据仍然可以通过其他指向同一个文件的链接访问到。只有当文件的链接数为0的时候,才表示该节点以及其指向的数据不再被使用,磁盘上的响应位置就会被标记为可用空间。
使用系统调用会影响系统的性能。与函数调用相比,系统调用的开销要大些,因为在之星系统调用时,Linux必须从运行用户代码切换到执行内核代码,然后再返回用户代码。
底层文件访问
- write系统调用
#include <unistd.h>
size_t write(int fields, const void *buf, size_t nbytes);
把缓冲区buf的前nbytes个字节写入与文件描述符fields关联的文件中,返回值为实际写入的字节数。
- read系统调用
size_t read(int fields, void * buf, size_t nbytes);
它返回实际读入的字节数,这可能会小于请求的字节数nbytes。如果read系统调用返回0,则代表未读入任何数据,已经达到文件尾。如果返回-1,则代表出错。
注意的是buf 绝对不包含实际的 C 字符串。C 字符串由标记字符串结束的单一 \0 字符终止。因为 read()
不将 \0 添加到缓冲区的结尾,在 read() 上使用 strlen()(或任何其它 C 字符串函数)将可能铸成大错!这种行为可以让 read() 和 write() 对包括 \0 字符的数据处理,而这对于一般字符串函数来说是不可能的。
- open系统调用
int open(const char *path, int oflag, mode_t mode);
成功返回一个文件描述符,如果两个程序同时打开同一个文件,他们会得到两个不同的文件描述符。如果这两个程序都对文件进行写操作,那么他们会各写各的,分别接着上次离开的位置继续写。他们的数据不会彼此交织在一起,而是互相覆盖。这是因为两个程序对文件的读写位置(偏移值)不同。可以通过文件锁来防止冲突。
oflag参数的值: O_RDONLY O_WRONLY O_RDWR。
oflag参数还有以下几个组合模式(用按位或):
-
- O_APPEND:写入数据追加在文件的末尾
- O_TRUNC:把文件长度设置为0,丢弃已有的内容。
- O_CREAT:按照参数mode给出的访问模式创建文件。
- O_EXCL:与O_CREAT一起使用。OPEN调用是一个原子操作,也就是说,它只执行一个函数调用。可以防止两个程序同时创建同一个文件。如果文件存在,Open系统调用则失败。
标准I/O库
标准I/O库及其头文件stdio.h为底层I/O系统调用提供了一个通用的借口。这个库现在已经成为ANSI标准C的一部分。在标准I/O库中,与底层文件描述符对应的是流stream,它被实现为结构FILE的指针。
fopen函数,fread,fwrite,fclose,fflush,fseek
stdio库在FILE结构里使用了一个内部缓冲区,只有在缓冲区满时才进行底层的系统调用。
文件和目录的维护
unlink系统调用可用来删除一个文件。rm程序使用的就是这个调用。