实现随机读写的关键是要按要求移动位置指针,这称为文件的定位。
1.文件定位
移动文件内部位置指针的函数主要有两个,即rewind()和fseek()。rewind函数前面已多次使用过,其调用形式为:
rewind(文件指针);
它的功能是把文件内部的位置指针移到文件首。
下面主要介绍fseek函数。fseek函数用来移动文件内部位置指针,其调用形式为:
fseek(文件指针,位移量,起始点);
其中:
l “文件指针”指向被移动的文件。
l “位移量”表示移动的字节数,要求位移量是long型数据,以便在文件长度大于64KB 时不会出错。当用常量表示位移量时,要求加后缀“L”。
l “起始点”表示从何处开始计算位移量,规定的起始点有三种:文件首,当前位置和文件尾。其表示方法如表8-2所示:
表8-2 文件位移量
起始点 | 表示符号 | 数字表示 |
文件首 | SEEK_SET | 0 |
当前位置 | SEEK_CUR | 1 |
文件末尾 | SEEK_END | 2 |
例如:
fseek(fp,100L,0);
其意义是把位置指针移到离文件首100个字节处。还要说明的是fseek函数一般用于二进制文件。在文本文件中由于要进行转换,故往往计算的位置会出现错误。
【例8-9】从键盘输入10个字符,写入文件f3.txt中,再重新读出,输出到屏幕上。
#include<stdio.h>
#include<stdlib.h>
int main()
{
int i;
char ch;
FILE *fp;
if((fp=fopen("D://C实例//f3.txt","r+"))==NULL)
{
printf("Cannot open file f3.txt!\n!");
exit(0);
}
for(i=0;i<10;i++)
{
ch=getchar();
fputc(ch,fp);
}
rewind(fp);
for(i=0;i<10;i++)
{
ch=fgetc(fp);
putchar(ch);
}
if(fclose(fp))
{
printf("Can not close file!\n");
exit(0);
}
printf("\n");
return 0;
}
程序运行结果:
helloworld↙
helloworld
文件f3.txt如图8-7所示。
图8-7 文件f3.txt
【例8-10】在例8-8的学生文件student中读出第二个学生的数据。
#include<stdio.h>
struct stu
{
char name[10];
int num;
int age;
char addr[15];
}boy,*qq;
int main()
{
FILE *fp;
char ch;
int i=1;
qq=&boy;
if((fp=fopen("student","rb"))==NULL)
{
printf("Cannot open file strike any key exit!");
getch();
exit(1);
}
rewind(fp);
fseek(fp,i*sizeof(structstu),0);
fread(qq,sizeof(structstu),1,fp);
printf("name\tnumber age addr\n");
printf("%s\t%5d %7d %s\n",qq->name,qq->num,qq->age,qq->addr);
}
程序运行结果:
name number age addr
李四 20120102 19 湖南衡阳
本实例用随机的方法读出文件中第二个学生的数据,以读二进制文件方式打开文件,移动文件位置指针,从文件头开始,移动一个stu类型的长度,然后再读出的数据即为第二个学生的数据。
在移动位置指针之后,即可用前面介绍的任一种读写函数进行读写。由于一般是读写一个数据块,因此常用fread和fwrite函数。
C语言中常用的文件检测函数有以下几个。
(1) 文件结束检测函数feof函数调用格式:
feof(文件指针);
判断文件是否处于文件结束位置,如文件结束,则返回值为1,否则为0。
(2) 读写文件出错检测函数ferror函数调用格式:
ferror(文件指针);
检查文件在用各种输入输出函数进行读写时是否出错。如ferror返回值为0表示未出错,否则表示有错。
(3) 文件出错标志和文件结束标志置0函数clearerr函数调用格式:
clearerr(文件指针);
该函数用于清除出错标志和文件结束标志,使它们为0值。
为了保障系统安全,通常采取用户帐号和密码登录系统。系统用户信息存放在一个文件中,系统帐号名和密码由若干字母与数字字符构成,因安全需要文件中的密码不能是明文,必须要经过加密处理。
【例8-11】输入5个用户信息(包含帐号名和密码)并写入文件f12-2.dat。要求文件中每个用户信息占一行,帐号名和加密过的密码之间用一个空格分隔。
密码加密算法:对每个字符ASCII码的低四位求反,高四位保持不变(即将其与15进行异或)
#include <stdio.h>
#include <string.h>
#include <process.h>
struct sysuser
{ /*定义系统用户帐号信息结构*/
charusername[20];
charpassword[8];
};
int main(void)
{
FILE *fp; /*1.定义文件指针*/
int i;
void encrypt(char *pwd);
struct sysusersu;
/*2.打开文件,进行写入操作*/
if((fp=fopen("User.txt","w"))== NULL)
{
printf("File open error!\n");
exit(0);
}/*3. 将5位用户帐号信息写入文件*/
for(i=1;i<=5;i++)
{
printf("Enter %ith sysuser(name password):",i);
scanf("%s%s",su.username,su.password); /*输入用户名和密码 */
encrypt(su.password); /*进行加密处理*/
fprintf(fp,"%s%s\n",su.username,su.password); /*写入文件*/
}
if(fclose(fp))
{ /*4.关闭文件*/
printf("Can not close the file!\n");
exit(0);
}
return 0;
}
/*加密算法*/
void encrypt(char *pwd)
{
int i;
/*与15(二进制码是00001111)异或,实现低四位取反,高四位保持不变*/
for(i=0;i<strlen(pwd);i++)
pwd[i] =pwd[i] ^ 15;
}
程序运行结果:
Enter 1th sysuser(name password):admin 123↙
Enter 2th sysuser(name password):test test↙
Enter 3th sysuser(name password):zhang zhang↙
Enter 4th sysuser(name password):li li↙
Enter 5th sysuser(name password):chen chen↙
加密后写入User.txt文件中,文件内容如图8-8所示。
图8-8 加密后User.txt文件内容