在Linux下编程,类似打印输入操作,又或者是条件判断循环等等,和在Windows下使用C语言没有区别,可以直接从文件IO开始学习,因为这部分涉及系统调用和编程接口,与Linux的特性有关,和我们熟知的Windows有一定区别。
系统调用
是一种程序接口,能让程序员在用户模式下使用到内核功能,这个过程是通过软中断的机制,向内核提交请求,以获取内核服务接口。一般来说用户模式下是无法直接访问内核的,因为内核关系到系统的安全。
Linux的系统调用相当精简,只有两百多个,都是最基础最有用的功能,具体是哪些一一列出来凑篇幅也没有意义,到时候自然会记住。
编程接口
系统调用是内核功能的程序接口(或者说函数),编程接口就是系统调用的,但并不是一一对应的关系,主要通过C库实现。
Linux中的文件区分
之前有介绍过,Linux中的文件系统,分为四种文件:普通文件,目录文件、链接文件、设备文件。
内核通过文件描述符来区分他们,这是一个非负的索引值,指向进程中打开文件记录表(记录已经打开的文件的表)。使用open操作打开一个文件时,便会得到一个文件描述符,我们通过这个描述符来对文件进行定位进行操作。
补充一点,每个进程启动时,在他的打开文件记录表中都会有三个文件,分别是标准输入、标准输出和标准错误处理,对应的描述符分别是0/1/2.但使用时最好用其宏定义。
基本文件操作
文件操作也需要包含头文件types.h stat.h fcnt.h unistd.h
函数返回值为负数(-1)则表示出错。
文件在传参过程中尽可能的使用宏定义,可以提高阅读性。
open();
需要传入路径名,打开方式,存取权限
close();
只需要传入获得的文件描述符即可关闭。
read();
需要传入文件描述符、读出的数据缓冲区、读出字节数
write();
需要传入文件描述符,写入数据缓冲区,写入的字节数
lseek();
需要传入文件描述符,偏移量,当前位置基点
文件锁
当多个用户需要同事访问同一文件时,又不允许,便使用文件锁来避免共享资源产生竞争状态。
文件锁分为建议性锁和强制性锁,一般来说不怎么使用建议性锁。
lockf();//施加建议性锁
fcnt();//施加强制锁,还能对记录上锁
需要传入文件描述符、控制指令、记录锁状态
对于记录锁,又分为读取锁和写入锁
读取锁:多个进程都能在文件的同一部分建立读取锁,实现文件的读共享
写入锁:限制其他进程在文件上的写入,实现写互斥
锁
struct flock
{
short l_type;
off_t l_start;
short l_whence;
off_t l_len;
pid_t l_pid;
}
多路复用
什么是多路复用?简单说就是用一路通道实现多路不同的数据传输。采用的技巧往往是分时复用。
IO处理模型
阻塞IO:
若某一进程的IO不能完成任务,该进程就会挂起,直到能够完成的条件出现,才能继续执行。一般在处理管道设备、终端设备和网络设备的读写时,会出现这种情况。
非阻塞IO:
若某一进程的IO不能完成任务,则执行IO操作的函数立即返回,并且返回出错。或者0。
IO多路转接模型:
当IO操作阻塞,让其中一个函数等待,等待期间能进行其他操作。常用的是select函数和poll函数。
信号驱动IO:
类似中断,由内核通知用户何时可以启动IO——安装一个信号处理重新,当捕捉到特定信号时,启动IO。
异步IO模型:
当数据准备好时,才启动IO。
标准IO
所谓标准IO,也就是对于数据流的IO,之前的IO都建立在文件的基础上。
标准IO的目的是减少read/write的调用,对于数据流标准IO提供三种类型的缓冲数据。
全缓冲:填满IO缓存后才进行IO操作。存放在磁盘上的文件通常是由标准IO库实现。比如malloc使用的就是全缓冲。
行缓冲:在输入输出过程中遇到行结束符,才执行IO操作,运行一次输出一个字符(fputc),但只有写了一行后才进行实际的IO。
不带缓冲:相当于write操作,不对字符进行缓冲,一般标准出错使用这种方式,使错误信息能尽快显示。
标准操作
打开文件
fopen/fdopen/freopen
以不同方式打开文件,但都返回一个FILE的指针。
关闭文件
fclose
将缓冲区的数据全部写入到文件中,并释放该文件资源。
读/写文件
fread/fwrite
这样看好像和之前说的文件操作也没差别,为什么还要把二者分开?之前在讲文件IO时有一个函数叫lseek(),他的作用是定位文件指针在相应的位置,而这个指针就是我们每次read或者write的位置。
这样看,如果我们使用普通的文件操作,每次进行IO操作都要进行指针位置的更改,写入10个字符需要更改10次,每次写入都要重新调用write。但如果采用标准IO,我们可以将要输出的字符暂存,再作为一个数据流一次性输出。
十次系统调用和一次系统调用的开销显然是不一样的,这样也就做到了前面说的降低write/read等系统调用次数的目的。
这些都是个人理解,如若有误,欢迎指正。
其他标准IO
字符IO
putc/fputc/putchar getc/fgetc/getchar
行IO
gets/fgets puts/fputs
格式化IO
printf/scanf