传智播客_C提高讲义

欢迎阅读

fprintf()和fscanf()同printf()和scanf()函数类似,不同之处就是printf()函数是想显示器输出,fprintf()则是向流指针指向的文件输出;fscanf()是从文件输入。

下面程序是向文件test.dat里输入一些字符: #include main() {

char *s=\ int i=617; FILE *fp;

fp=fopne(\

fputs(\ fputc(':', fp); fprintf(fp, \ fprintf(fp, \ fclose(fp); }

用DOS的TYPE命令显示TEST.DAT的内容如下所示: 屏幕显示 Your score of TOEFL is: 617 That's good news 下面的程序是把上面的文件test.dat里的内容在屏幕上显示出来: #include main() {

char *s, m[20]; int i; FILE *fp; fp=fopen(\ fgets(s, 24, fp); printf(\ fscanf(fp, \ printf(\ putchar(fgetc(fp)); fgets(m, 17, fp); puts(m); fclose(fp); getch(); }

运行后屏幕显示:

Your score of TOEFL is: 617 That's good news

4.清除和设置文件缓冲区 (1).清除文件缓冲区函数: int fflush(FILE *stream); int flushall(); 欢迎阅读

欢迎阅读

fflush()函数将清除由stream指向的文件缓冲区里的内容,常用于写完一些数据后,立即用该函数清除缓冲区,以免误操作时,破坏原来的数据。

flushall()将清除所有打开文件所对应的文件缓冲区。 (2).设置文件缓冲区函数

void setbuf(FILE *stream,char *buf);

void setvbuf(FILE *stream,char *buf,int type,unsigned size);

这两个函数将使得打开文件后,用户可建立自己的文件缓冲区,而不使用fopen()函数打开文件设定的默认缓冲区。

对于setbuf()函数,buf指出的缓冲区长度由头文件stdio.h中定义的宏BUFSIZE的值决定,缺省值为512字节。当选定buf为空时,setbuf函数将使的文件I/O不带缓冲。而对setvbuf函数,则由malloc函数来分配缓冲区。参数size指明了缓冲区的长度(必须大于0),而参数type则表示了缓冲的类型,其值可以取如下值: type 值 含义 _IOFBF 文件全部缓冲,即缓冲区装满后,才能对文件读写 _IOLBF 文件行缓冲,即缓冲区接收到一个换行符时,才能对文件读写 _IONBF 文件不缓冲,此时忽略buf,size的值,直接读写文件,不再经过文件缓冲区缓冲

5.文件的随机读写函数 前面介绍的文件的字符/字符串读写,均是进行文件的顺序读写,即总是从文件的开头开始进行读写。这显然不能满足我们的要求,C语言提供了移动文件指针和随机读写的函数,它们是: (1).移动文件指针函数: long ftell(FILE *stream); int rewind(FILE *stream); fseek(FILE *stream,long offset,int origin); 函数ftell()用来得到文件指针离文件开头的偏移量。当返回值是-1时表示出错。 rewind()函数用于文件指针移到文件的开头,当移动成功时,返回0,否则返回一个非0值。 fseek()函数用于把文件指针以origin为起点移动offset个字节,其中origin指出的位置可有以下几种: origin 数值 代表的具体位置 SEEK_SET 0 文件开头 SEEK_CUR 1 文件指针当前位置 SEEK_END 2 文件尾 例如:

fseek(fp,10L,0); 把文件指针从文件开头移到第10字节处,由于offset参数要求是长整型数,故其数后带L。 fseek(fp,-15L,2); 把文件指针从文件尾向前移动15字节。 (2).文件随机读写函数

int fread(void *ptr,int size,int nitems,FILE *stream); int fwrite(void *ptr,int size,int nitems,FILE *stream);

fread()函数从流指针指定的文件中读取nitems个数据项,每个数据项的长度为size个字节,读取的nitems数据项存入由ptr指针指向的内存缓冲区中, 在执行fread()函数时,文件指针随着读取的字节数而向后移动,最后移动结束的位置等于实际读出的字节数。该函数执行结束后,将返回实际读出的数据项数,

这个数据项数不一定等于设置的nitems,因为若文件中没有足够的数据项,或读中间出错,都会导致返回的数据项数少于设置的nitems。当返回数不等于nitems时 欢迎阅读

欢迎阅读

,可以用feof()或ferror()函数进行检查。

fwrite()函数从ptr指向的缓冲区中取出长度为size字节的nitems个数据项,写入到流指针stream指向的文件中,执行该操作后,文件指针将向后移动,

移动的字节数等于写入文件的字节数目。该函数操作完成后,也将返回写入的数据项数。 6.2.3非标准文件的读写

这类函数最早用于UNIX操作系统,ANSI标准未定义,但有时也经常用到,DOS 3.0以上版本支持这些函数。它们的头文件为io.h。

由于我们不常用这些函数,所以在这里就简单说一下。 1.文件的打开和关闭

open()函数的作用是打开文件,其调用格式为: int open(char *filename, int access);

该函数表示按access的要求打开名为filename的文件,返回值为文件描述字,其中access有两部分内容:

基本模式和修饰符, 两者用\或\方式连接。修饰符可以有多个, 但基本模式只能有一个。 access的规定 -------------------------------------------------------- 基本模式 含义 修饰符 含 义 -------------------------------------------------------- O_RDONLY 只读 O_APPEND 文件指针指向末尾 O_WRONLY 只写 O_CREAT 文件不存在时创建文件, 属性按基本模式属性 O_RDWR 读写 O_TRUNC 若文件存在, 将其长度缩为0, 属性不变 O_BINARY 打开一个二进制文件 O_TEXT 打开一个文字文件 --------------------------------------------------------- open()函数打开成功, 返回值就是文件描述字的值(非负值), 否则返回-1。 close()函数的作用是关闭由open()函数打开的文件, 其调用格式为: int close(int handle); 该函数关闭文件描述字handle相连的文件。 2.读写函数 int read(int handle, void *buf, int count); read()函数从handle(文件描述字)相连的文件中, 读取count个字节放到buf所指的缓冲区中,

返回值为实际所读字节数, 返回-1表示出错。返回0 表示文件结束。 write()函数的调用格式为: int write(int handle, void *buf, int count); write()函数把count个字节从buf指向的缓冲区写入与handle相连的文件中, 返回值为实际写入的字节数。 3.随机定位函数

lseek()函数的调用格式为:

int lseek(int handle, long offset, int fromwhere);

该函数对与handle相连的文件位置指针进行定位,功能和用法与fseek()函数相同。 tell()函数的调用格式为: long tell(int handle);

该函数返回与handle相连的文件现生位置指针, 功能和用法与ftell()相同 6.2.4注意点 文本文件: ASCII文件,每个字节存放一个字符的ASCII码 欢迎阅读 欢迎阅读 二进制文件:数据按其在内存中的存储形式原样存放 项目开发中参考fgets函数的实现方法 fgets(buf, bufMaxLen, fp); 对fgets函数来说,n必须是个正整数,表示从文件按中读出的字符数不超过n-1,存储到字符数组str中,并在末尾加上结束标志’\\0’,换言之,n代表了字符数组的长度,即sizeof(str)。如果读取过程中遇到换行符或文件结束标志,读取操作结束。若正常读取,返回指向str代表字符串的指针,否则,返回NULL(空指针)。 6.3文件操作案例-配置文件读写 配置文件读写案例实现分析

1、功能划分 a) 界面测试(功能集成) 自己动手规划接口模型。 b) 配置文件读写 i. 配置文件读(根据key,读取valude) ii. 配置文件写(输入key、valude) iii. 配置文件修改(输入key、valude) iv. 优化 ===》接口要求紧 模块要求松 2、实现及代码讲解 3、测试。 6.4文件操作案例-大文件加解密 功能实现分析 1、数据加密解密接口测试 2、数据加密过程分析 文件数据的movecopy + 数据加密 3、数据加解密功能集成 数据加密和解密分为两个版本 打padding 和不打padding 数据加密解密原理 7 C接口的封装和设计专题 Win32环境下动态链接库(DLL)编程原理 比较大的程序都由很多模块组成,这些模块分别完成相对独立的功能,它们彼此协作来完成整个软件系统的工作。其中可能存在一些模块的功能较为,在构造其它软件系统时仍会被使用。在构造软件系统时,如果将所有模块的都静态编译到整个应用程序EXE文件中,会产生一些问题:一个缺点是增加了应用程序的大小,它会占用更多的磁盘空间,程序运行时也会消耗较大的空间,造成系统资源的浪费;另一个缺点是,在编写大的EXE程序时,在每次修改重建时都必须调整编译所有源代码,增加了编译过程的复杂性,也不利于阶段性的单元。

Windows系统平台上提供了一种完全不同的较有效的编程和运行环境,你可以将独立的程序模块创建为较小的DLL(Linkable Library)文件,并可对它们单独编译和测试。在运行时,只有当EXE程序确实要调用这些DLL模块的情况下,系统才会将它们装载到内存空间中。这种 方式不仅减少了EXE文件的大小和对内存空间的需求,而且使这些DLL模块可以同时被多个应用程序使用。Windows自己就将一些主要的系统功能以DLL模块的形式实现。例如IE中的一些基本功能就是由DLL文件实现的,它可以被其它应用程序调用和集成。 欢迎阅读

欢迎阅读

一般来说,DLL是一种磁盘文件(通常带有DLL扩展名),它由全局数据、服务函数和资源组成,在运行时被系统加载到进程的虚拟空间中,成为调用进程的 一部分。如果与其它DLL之间没有冲突,该文件通常映射到进程虚拟空间的同一地址上。DLL模块中包含各种导出函数,用于向外界提供服务。Windows 在加载DLL模块时将进程函数调用与DLL文件的导出函数相匹配。

在Win32环境中,每个进程都复制了自己的读/写全局变量。如果想要与其它进程共享内存,必须使用内存映射文件或者声明一个共享数据段。DLL模块需要的堆栈内存都是从运行进程的堆栈中分配出来的。

DLL现在越来越容易编写。Win32已经大大简化了其编程模式,并有许多来自AppWizard和MFC类库的支持。

一、导出和导入函数的匹配

DLL文件中包含一个导出函数表。这些导出函数由它们的符号名和称为标识号的整数与外界联系起来。函数表中还包含了DLL中函数的地址。当应用程序加载 DLL模块时时,它并不知道调用函数的实际地址,但它知道函数的符号名和标识号。动态链接过程在加载的DLL模块时动态建立一个函数调用与函数地址的对应 表。如果重新编译和重建DLL文件,并不需要修改应用程序,除非你改变了导出函数的符号名和参数序列。

简单的DLL文件只为应用程序提供导出函数,比较复杂的DLL文件除了提供导出函数以外,还调用其它DLL文件中的函数。这样,一个特殊的DLL可以既有导入函数,又有导入函数。这并不是一个问题,因为动态链接过程可以处理交叉相关的情况。

在DLL代码中,必须像下面这样明确声明导出函数:

__declspec(dllexport) int MyFunction(int n);

但也可以在模块定义(DEF)文件中列出导出函数,不过这样做常常引起更多的麻烦。在应用程序方面,要求像下面这样明确声明相应的输入函数:

__declspec(dllimport) int MyFuncition(int n);

仅有导入和导出声明并不能使应用程序内部的函数调用链接到相应的DLL文件上。应用程序的项目必须为链接程序指定所需的输入库(LIB文件)。而且应用程序事实上必须至少包含一个对DLL函数的调用。

二、与DLL模块建立链接

应用程序导入函数与DLL文件中的导出函数进行链接有两种方式:隐式链接和显式链接。所谓的隐式链接是指在应用程序中不需指明DLL文件的实际存储路径,程序员不需关心DLL文件的实际装载。而显式链接与此相反。

欢迎阅读

联系客服:779662525#qq.com(#替换为@) 苏ICP备20003344号-4