ImageVerifierCode 换一换
你正在下载:

实例.docx

[预览]
格式:DOCX , 页数:24 ,大小:26.07KB ,
资源ID:8964524      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bingdoc.com/d-8964524.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(实例.docx)为本站会员(b****8)主动上传,冰点文库仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰点文库(发送邮件至service@bingdoc.com或直接QQ联系客服),我们立即给予删除!

实例.docx

1、实例实例fopen和getc函数的实现下面以标准库函数fopen 和getc 的一种实现方法为例来说明如何将这些系统调用结合起来使用。我们回忆一下,标准库中的文件不是通过文件描述符描述的,而是使用文件指针描述的。文件指针是一个指向包含文件各种信息的结构的指针,该结构包含下列内容:一个指向缓冲区的指针,通过它可以一次读入文件的一大块内容;一个记录缓冲区中剩余的字符数的计数器;一个指向缓冲区中下一个字符的指针;文件描述符;描述读写模式的标志;描述错误状态的标志等。描述文件的数据结构包含在头文件中,任何需要使用标准输入输出库中函数的程序都必须在源文件中包含这个头文件(通过#include指令包含头文

2、件)。此文件也被库中的其它函数包含。在下面这段典型的代码段中,只供标准库中其它函数所使用的名字以下划线开始,因此一般不会与用户程序中的名字冲突。所有的标准库函数都遵循该约定。#define NULL 0#define EOF (-1)#define BUFSIZ 1024#define OPEN_MAX 20 /* max #files open at once */typedef struct _iobuf int cnt; /* characters left */char *ptr; /* next character position */char *base; /* location

3、 of buffer */int flag; /* mode of file access */int fd; /* file descriptor */ FILE;extern FILE _iobOPEN_MAX;#define stdin (&_iob0)#define stdout (&_iob1)#define stderr (&_iob2)enum _flags _READ = 01, /* file open for reading */_WRITE = 02, /* file open for writing */_UNBUF = 04, /* file is unbuffere

4、d */_EOF = 010, /* EOF has occurred on this file */_ERR = 020 /* error occurred on this file */;int _fillbuf(FILE *);int _flushbuf(int, FILE *);#define feof(p) (p)-flag & _EOF) != 0)#define ferror(p) (p)-flag & _ERR) != 0)#define fileno(p) (p)-fd)#define getc(p) (-(p)-cnt = 0 ? (unsigned char) *(p)-

5、ptr+ : _fillbuf(p)#define putc(x,p) (-(p)-cnt = 0 ? *(p)-ptr+ = (x) : _flushbuf(x),p)#define getchar() getc(stdin)#define putcher(x) putc(x), stdout)宏getc 一般先将计数器减1,将指针移到下一个位置,然后返回字符。(前面讲过,一个长的#define语句可用反斜杠分成几行。)但是,如果计数值变为负值,getc就调用函数_fillbuf填充缓冲区,重新初始化结构的内容,并返回一个字符。返回的字符为unsigned类型。以确保所有的字符为正值。尽管在

6、这里我们并不想讨论一些细节,但程序中还是给出了putc函数的定义,以表明它的操作与getc 函数非常类似,当缓冲区满时,它将调用函数_flushbuf。此外,我们还在其中包含了访问错误输出、文件结束状态和文件描述符的宏。下面我们来着手编写函数fopen。fopen函数的主要功能是打开文件,定位到合适的位置,设置标志位以指示相应的状态。它不分配任何缓冲区空间,缓冲区的分配是在第一次读文件时由函数_fillbuf完成的。#include #include syscalls.h#define PERMS 0666 /* RW for owner, group, others */FILE *fope

7、n(char *name, char *mode)int fd;FILE *fp;if (*mode != r & *mode != w & *mode != a)return NULL;for (fp = _iob; fp flag & (_READ | _WRITE) = 0)break; /* found free slot */if (fp = _iob + OPEN_MAX) /* no free slots */return NULL;if (*mode = w)fd = creat(name, PERMS);else if (*mode = a) if (fd = open(na

8、me, O_WRONLY, 0) = -1)fd = creat(name, PERMS);lseek(fd, 0L, 2); elsefd = open(name, O_RDONLY, 0);if (fd = -1) /* couldnt access name */return NULL;fp-fd = fd;fp-cnt = 0;fp-base = NULL;fp-flag = (*mode = r) ? _READ : _WRITE;return fp;该版本的fopen函数没有涉及标准C的所有访问模式,但是,加入这些模式并不需要增加多少代码。特别是,该版本的fopen 不能识别表示二

9、进制访问方式的b 标志,这是因为,在UNIX 系统中这种方式是没有意义的。同时,它也不能识别允许同时进行读和写的+标志。对于某一特定的文件,第一次调用getc 函数时计数值为0,这样就必须调用一次函数_fillbuf。如果_fillbuf发现文件不是以读方式打开的,它将立即返回EOF;否则,它将试图分配一个缓冲区(如果读操作是以缓冲方式进行的话)。建立缓冲区后,_fillbuf调用read填充此缓冲区,设置计数值和指针,并返回缓冲区中的第一个字符。随后进行的_fillbuf调用会发现缓冲区已经分配。#include syscalls.h/* _fillbuf: allocate and fil

10、l input buffer */int _fillbuf(FILE *fp)int bufsize;if (fp-flag&(_READ|_EOF_ERR) != _READ)return EOF;bufsize = (fp-flag & _UNBUF) ? 1 : BUFSIZ;if (fp-base = NULL) /* no buffer yet */if (fp-base = (char *) malloc(bufsize) = NULL)return EOF; /* cant get buffer */fp-ptr = fp-base;fp-cnt = read(fp-fd, fp

11、-ptr, bufsize);if (-fp-cnt cnt = -1)fp-flag |= _EOF;elsefp-flag |= _ERR;fp-cnt = 0;return EOF;return (unsigned char) *fp-ptr+;最后一件事情便是如何执行这些函数。我们必须定义和初始化数组_iob 中的stdin、stdout和stderr值:FILE _iobOPEN_MAX = /* stdin, stdout, stderr */ 0, (char *) 0, (char *) 0, _READ, 0 , 0, (char *) 0, (char *) 0, _WRI

12、TE, 1 , 0, (char *) 0, (char *) 0, _WRITE, | _UNBUF, 2 ;该结构中flag部分的初值表明,将对stdin执行读操作、对stdout执行写操作、对stderr执行缓冲方式的写操作。练习 8-2 用字段代替显式的按位操作,重写fopen 和_fillbuf 函数。比较相应代码的长度和执行速度。练习 8-3 设计并编写函数_flushbuf、fflush和fclose。练习 8-4 标准库函数int fseek(FILE *fp, long offset, int origin)类似于函数lseek,所不同的是,该函数中的fp是一个文件指针而不是

13、文件描述符,且返回值是一个int类型的状态而非位置值。编写函数fseek,并确保该函数与库中其它函数使用的缓冲能够协同工作。8.6. 实例目录列表我们常常还需要对文件系统执行另一种操作,以获得文件的有关信息,而不是读取文件的具体内容。目录列表程序便是其中的一个例子,比如_UNIX 命令ls,它打印一个目录中的文件名以及其它一些可选信息,如文件长度、访问权限等等。MS-DOS操作系统中的dir 命令也有类似的功能。由于UNIX 中的目录就是一种文件,因此,ls 只需要读此文件就可获得所有的文件名。但是,如果需要获取文件的其它信息,比如长度等,就需要使用系统调用。在其它一些系统中,甚至获取文件名也

14、需要使用系统调用,例如在MS-DOS 系统中即如此。无论实现方式是否同具体的系统有关,我们需要提供一种与系统无关的访问文件信息的途径。以下将通过程序fsize说明这一点。fsize程序是ls命令的一个特殊形式,它打印命令行参数表中指定的所有文件的长度。如果其中一个文件是目录,则fsize程序将对此目录递归调用自身。如果命令行中没有任何参数,则fsize程序处理当前目录。我们首先回顾UNIX 文件系统的结构。在UNIX 系统中,目录就是文件,它包含了一个文件名列表和一些指示文件位置的信息。“位置”是一个指向其它表(即i 结点表)的索引。文件的i结点是存放除文件名以外的所有文件信息的地方。目录项通

15、常仅包含两个条目:文件名和i结点编号。遗憾的是,在不同版本的系统中,目录的格式和确切的内容是不一样的。因此,为了分离出不可移植的部分,我们把任务分成两部分。外层定义了一个称为Dirent 的结构和3 个函数opendir、readdir和closedir,它们提供与系统无关的对目录项中的名字和i 结点编号的访问。我们将利用此接口编写fsize程序,然后说明如何在与Version 7和System VUNIX 系统的目录结构相同的系统上实现这些函数。其它情况留作练习。结构Dirent包含i结点编号和文件名。文件名的最大长度由NAMZ_MAX设定,NAME_MAX的值由系统决定。opendir返回

16、一个指向称为DIR的结构的指针,该结构与结构FILE类似,它将被readdir和closedir使用。所有这些信息存放在头文件dirent.h中。#define NAME_MAX 14 /* longest filename component; */* system-dependent */typedef struct /* portable directory entry */long ino; /* inode number */char nameNAME_MAX+1; /* name + 0 terminator */ Dirent;typedef struct /* minimal

17、DIR: no buffering, etc. */int fd; /* file descriptor for the directory */Dirent d; /* the directory entry */ DIR;DIR *opendir(char *dirname);Dirent *readdir(DIR *dfd);void closedir(DIR *dfd);系统调用stat以文件名作为参数,返回文件的i结点中的所有信息;若出错,则返回-1。如下所示:char *name;struct stat stbuf;int stat(char *, struct stat *);s

18、tat(name, &stbuf);它用文件name 的i 结点信息填充结构stbuf。头文件中包含了描述stat的返回值的结构。该结构的一个典型形式如下所示:struct stat /* inode information returned by stat */dev_t st_dev; /* device of inode */ino_t st_ino; /* inode number */short st_mode; /* mode bits */short st_nlink; /* number of links to file */short st_uid; /* owners us

19、er id */short st_gid; /* owners group id */dev_t st_rdev; /* for special files */off_t st_size; /* file size in characters */time_t st_atime; /* time last accessed */time_t st_mtime; /* time last modified */time_t st_ctime; /* time originally created */;该结构中大部分的值已在注释中进行了解释。dev_t 和ino_t 等类型在头文件中定义,程序

20、中必须包含此文件。st_mode项包含了描述文件的一系列标志,这些标志在中定义。我们只需要处理文件类型的有关部分:#define S_IFMT 0160000 /* type of file: */#define S_IFDIR 0040000 /* directory */#define S_IFCHR 0020000 /* character special */#define S_IFBLK 0060000 /* block special */#define S_IFREG 0010000 /* regular */* . */下面我们来着手编写程序fsize。如果由stat 调用获得

21、的模式说明某文件不是一个目录,就很容易获得该文件的长度,并直接输出。但是,如果文件是一个目录,则必须逐个处理目录中的文件。由于该目录可能包含子目录,因此该过程是递归的。主程序main处理命令行参数,并将每个参数传递给函数fsize。#include #include #include syscalls.h#include /* flags for read and write */#include /* typedefs */#include /* structure returned by stat */#include dirent.hvoid fsize(char *)/* print

22、file name */main(int argc, char *argv)if (argc = 1) /* default: current directory */fsize(.);elsewhile (-argc 0)fsize(*+argv);return 0;函数fsize打印文件的长度。但是,如果此文件是一个目录,则fsize首先调用dirwalk函数处理它所包含的所有文件。注意如何使用文件中的标志名S_IFMT 和S_IFDIR 来判定文件是不是一个目录。括号是必须的,因为&运算符的优先级低于=运算符的优先级。int stat(char *, struct stat *);voi

23、d dirwalk(char *, void (*fcn)(char *);/* fsize: print the name of file name */void fsize(char *name)struct stat stbuf;if (stat(name, &stbuf) = -1) fprintf(stderr, fsize: cant access %sn, name);return;if (stbuf.st_mode & S_IFMT) = S_IFDIR)dirwalk(name, fsize);printf(%8ld %sn, stbuf.st_size, name);函数d

24、irwalk 是一个通用的函数,它对目录中的每个文件都调用函数fcn 一次。它首先打开目录,循环遍历其中的每个文件,并对每个文件调用该函数,然后关闭目录返回。因为fsize函数对每个目录都要调用dirwalk函数,所以这两个函数是相互递归调用的。#define MAX_PATH 1024/* dirwalk: apply fcn to all files in dir */void dirwalk(char *dir, void (*fcn)(char *)char nameMAX_PATH;Dirent *dp;DIR *dfd;if (dfd = opendir(dir) = NULL)

25、fprintf(stderr, dirwalk: cant open %sn, dir);return;while (dp = readdir(dfd) != NULL) if (strcmp(dp-name, .) = 0| strcmp(dp-name, .)continue; /* skip self and parent */if (strlen(dir)+strlen(dp-name)+2 sizeof(name)fprintf(stderr, dirwalk: name %s %s too longn,dir, dp-name);else sprintf(name, %s/%s,

26、dir, dp-name);(*fcn)(name);closedir(dfd);每次调用readdir都将返回一个指针,它指向下一个文件的信息。如果目录中已没有待处理的文件,该函数将返回NULL。每个目录都包含自身“.”和父目录“.”的项目,在处理时必须跳过它们,否则将会导致无限循环。到现在这一步为止,代码与目录的格式无关。下一步要做的事情就是在某个具体的系统上提供一个opendir、readdir和closedir的最简单版本。以下的函数适用于Version 7和System V UNIX 系统,它们使用了头文件(sys/dir.h中的目录信息,如下所示:#ifndef DIRSIZ#de

27、fine DIRSIZ 14#endifstruct direct /* directory entry */ino_t d_ino; /* inode number */char d_nameDIRSIZ; /* long name does not have 0 */;某些版本的系统支持更长的文件名和更复杂的目录结构。类型 ino_t是使用typedef定义的类型,它用于描述i结点表的索引。在我们通常使用的系统中,此类型为unsigned short,但是这种信息不应在程序中使用。因为不同的系统中该类型可能不同,所以使用typedef 定义要好一些。所有的“系统”类型可以在文件fd = f

28、d;return dp;closedir函数用于关闭目录文件并释放内存空间:/* closedir: close directory opened by opendir */void closedir(DIR *dp)if (dp) close(dp-fd);free(dp);最后,函数readdir使用read系统调用读取每个目录项。如果某个目录位置当前没有使用(因为删除了一个文件),则它的i 结点编号为0,并跳过该位置。否则,将i 结点编号和目录名放在一个static 类型的结构中,并给用户返回一个指向此结构的指针。每次调用readdir函数将覆盖前一次调用获得的信息。#include /* local directory structure */* readdir: read directory entries in sequence */Dirent *readdir(DIR *dp)struct direct dirbu

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2