unix系统接口
两个系统调用
int n_read=read(int fd,char *buf,int n);
int n_written=write(int fd,char *buf,int n);
对于系统调用read和write,第一个参数为文件描述符,第二个参数为程序中存放读或者写的字符数组,第三个参数为要传输的字节数。
用read构造getchar函数,因为没有重定向所以系统默认从标准输入中读即文件描述符0—stdin
下面这个版本 依次读一个字符并且返回一个字符。
#include <unistd>
int getchar(void)
{
char c;
return (read(0,&c,1)==1)?(unsigned char)c:EOF;
}
下面这个版本,依次读入一个数组并返回一个字符
#include <unistd>
int getchar(void)
{
static char buf[BUFSIZE];
static char *bufp=buf;
static int n=0;
if(n==0)
{
n=read(0,buf,sizeof(buf));
bufp=buf;
}
return (--n>=0)?(unsigned char)*bufp++:EOF;
}
问题:
调用函数第一次的时候,n初始化为0,执行n0时候的语句,从标准输入中读取字符串,并将bufp指向该字符数组。然后–n,并返回bufp指向的字符,并将bufp指向下一个字符。
但是第二次调用的时候,不担心n与bufp重新初始化,n=0,bufp指向第一个字符。等于重新输入没有缓冲区么。相当于只输出第一个字符,其他字符全被吞掉。
答:
不会,上述函数中的buf[BUFSIZE]声明为静态变量,此时静态变量只进行一次初始化操作,并且与局部变量不同的是,不会应为函数调用的结束,静态变量就消失,而实仍旧存在。
静态变量的生存周期与外部变量是一致的,不同点在于,静态变脸保护了数据,也可以比喻成静态变量就是将数据指明给某些特定函数使用的外部变量。
所以对于buf[BUFSIZE],bufp以及n这几个静态变量
1,只初始化一次;
2,–n>=0指明缓冲区还有字符
3,*bufp++将获得bufp指向的字符,并将bufp加一,
4,if当中的bufp=buf也是必须的,因为初始化只在第一次执行,在后面当n0时候,需要将bufp重新指向数组首位。
系统调用open与creat
open
#include <fcntl.h>
int fd;
int open(char *name,int flags,int perms);
fd=open(name,flags,perms);
open中
第一个参数为文件名称。
第二个参数为文件打开方式,在<fcntl.h>中定义,有
O_RDONLY
O_WDONLY
O_EDWR
意义如名称,只读,只写,读写
第三个参数为访问权限。
返回值为文件描述符
open打开一个不存在的文件将发生错误,可以用creat创建或覆盖已有的旧文件。
creat
int creat(char *name,int perms);
fd=creat(name,perms);
creat
第一个参数为文件名
第二个参数为访问权限。访问权限用三位的8进制数描述
返回值为,正常返回一个文件描述符,错误返回-1.
下面为一个简化版本的unix程序cp
#include <stdio.h>
#include <fcntl.h>
#include <unistd>
#define PERMS 0666
int main(int rgc,char *argv[])
{
int f1,f2,n;
char buf[BUFSIZE];
if(argc!=3)
{
fprintf(stderr,"Usage:cp from to");
}
if((f1=open(argv[1],O_RDONLY,0))==-1)
{
fprintf(stderr,"cp:cant open %s",argv[1]);
}
if((f2=creat(argv[2],PERMS))==-1)
{
fprintf(stderr,"cp:cant creat %s.mode %03o",argv[2],PERMS);
}
while((n=read(f1,buf,BUFSIZE))>0)
{
if(write(f2,buf,n)!=n)
{
fprintf(stderr,"cp:write error on file %s",argv[2]);
}
}
return 0;
}
上述的函数,仅仅复制一个文件,不允许目录作为第二个参数 ,并且目标文件的权限不是通过复制得到的,而实通过重新定义。
可以发现每次调用read和write进行读写的位置紧跟在前一次操作的位置之后。
有一种在文件中移动到任意位置的函数;
long Iseek(int fd,long offset,int origin);
fd为文件描述符,offset相对于origin的偏移量,origin值为0、 1、2.
语法意义为从文件开始、当前位置以及文件 结束开始算。