标志
含义
r, rb
以只读方式打开
w, wb
以只写方式打开。如果文件不存在,则创建该文件,否则文件被截断
a, ab
以追加方式打开。如果文件不存在,则创建该文件
r+, r+b, rb+
以读写方式打开
w+, w+b, wh+
以读写方式打开。如果文件不存在时,创建新文件,否则文件被截断
a+, a+b, ab+
以读和追加方式打开。如果文件不存在,创建新文件
其中b用于区分二进制文件和文本文件,这一点在DOS、Windows系统中是有区分的,但Linux不区分二进制文件和文本文件。
读写
C库函数支持以字符、字符串等为单位,支持按照某中格式进行文件的读写,这一组函数为:
int fgetc(FILE *stream);
int fputc(int c, FILE *stream);
char *fgets(char *s, int n, FILE *stream);
int fputs(const char *s, FILE *stream);
int fprintf(FILE *stream, const char *format, ...);
int fscanf (FILE *stream, const char *format, ...);
size_t fread(void *ptr, size_t size, size_t n, FILE *stream);
size_t fwrite (const void *ptr, size_t size, size_t n, FILE *stream);
fread()实现从流stream中读取加n个字段,每个字段为size字节,并将读取的字段放入ptr所指的字符数组中,返回实际已读取的字段数。在读
取的字段数小于num时,可能是在函数调用时出现错误,也可能是读到文件的结尾。所以要通过调用feof()和ferror()来判断。
write()实现从缓冲区ptr所指的数组中把n个字段写到流stream中,每个字段长为size个字节,返回实际写入的字段数。
另外,C库函数还提供了读写过程中的定位能力,这些函数包括
int fgetpos(FILE *stream, fpos_t *pos);
int fsetpos(FILE *stream, const fpos_t *pos);
int fseek(FILE *stream, long offset, int whence);
等。
关闭
利用C库函数关闭文件依然是很简单的操作:
int fclose (FILE *stream);
例程:将第2节中的例程用C库函数来实现。
#include <stdio.h>
#define LENGTH 100
main()
{
FILE *fd;
char str[LENGTH];
fd = fopen("hello.txt", "w+"); /* 创建并打开文件 */
if (fd)
{
fputs("Hello, Software Weekly", fd); /* 写入Hello, software weekly字符串 */
fclose(fd);
}
fd = fopen("hello.txt", "r");
fgets(str, LENGTH, fd); /* 读取文件内容 */
printf("%s"n", str);
fclose(fd);
}
4.小结
Linux提供的虚拟文件系统为多种文件系统提供了统一的接口,Linux的文件编程有两种途径:基于Linux系统调用;基于C库函数。这两
种编程所涉及到文件操作有新建、打开、读写和关闭,对随机文件还可以定位。本章对这两种编程方法都给出了具体的实例。
Linux下的C编程实战(三)
――进程控制与进程通信编程
1.Linux进程
Linux进程在内存中包含三部分数据:代码段、堆栈段和数据段。代码段存放了程序的代码。代码段可以为机器中运行同一程序的数个
进程共享。堆栈段存放的是子程序(函数)的返回地址、子程序的参数及程序的局部变量。而数据段则存放程序的全局变量、常数以及动态数
据分配的数据空间(比如用malloc函数申请的内存)。与代码段不同,如果系统中同时运行多个相同的程序,它们不能使用同一堆栈段和数据
段。
Linux进程主要有如下几种状态:用户状态(进程在用户状态下运行的状态)、内核状态(进程在内核状态下运行的状态)、内存中就绪(进程
没有执行,但处于就绪状态,只要内核调度它,就可以执行)、内存中睡眠(进程正在睡眠并且处于内存中,没有被交换到SWAP设备)、就绪
且换出(进程处于就绪状态,但是必须把它换入内存,内核才能再次调度它进行运行)、睡眠且换出(进程正在睡眠,且被换出内存)、被抢
先(进程从内核状态返回用户状态时,内核抢先于它,做了上下文切换,调度了另一个进程,原先这个进程就处于被抢先状态)、创建状态(
进程刚被创建,该进程存在,但既不是就绪状态,也不是睡眠状态,这个状态是除了进程0以外的所有进程的最初状态)、僵死状态(进程调用
exit结束,进程不再存在,但在进程表项中仍有记录,该记录可由父进程收集)。
下面我们来以一个进程从创建到消亡的过程讲解Linux进程状态转换的“生死因果”。
(1)进程被父进程通过系统调用fork创建而处于创建态;
(2)fork调用为子进程配置好内核数据结构和子进程私有数据结构后,子进程进入就绪态(或者在内存中就绪,或者因为内存不够而在SWAP设
备中就绪);
(3)若进程在内存中就绪,进程可以被内核调度程序调度到CPU运行;
(4)内核调度该进程进入内核状态,再由内核状态返回用户状态执行。该进程在用户状态运行一定时间后,又会被调度程序所调度而进入内核
状态,由此转入就绪态。有时进程在用户状态运行时,也会因为需要内核服务,使用系统调用而进入内核状态,服务完毕,会由内核状态转回
用户状态。要注意的是,进程在从内核状态向用户状态返回时可能被抢占,这是由于有优先级更高的进程急需使用CPU,不能等到下一次调度时
机,从而造成抢占;
(5)进程执行exit调用,进入僵死状态,最终结束。
2.进程控制
进程控制中主要涉及到进程的创建、睡眠和退出等,在Linux中主要提供了fork、exec、clone的进程创建方法,sleep的进程睡眠和exit的进程
退出调用,另外Linux还提供了父进程等待子进程结束的系统调用wait。
fork
对于没有接触过Unix/Linux操作系统的人来说,fork是最难理解的概念之一,它执行一次却返回两个值,完全“不可思议”。先看下面的程序
: