九 文件操作
1文件分类
1)按逻辑结构
a) 记录文件:由具有一定结构的记录组成(定长和不定长)
b) 流式文件:由一个个字符(字节)数据顺序组成
2) 按存储介质
a)普通文件:存储介质文件(磁盘、磁带等)
b)设备文件:非存储介质(键盘、显示器、打印机等)
3)按组织形式
a)文本文件:ASCII文件,每个字节存放一个字符的ASCII码
b)二进制文件:数据按其在内存中的存储形式原样存放
2 标准文件的读写
1) fopen(char *filename,char *type);//返回文件句柄FILE
参数type :
"r" 打开,只读
"w" 打开,文件指针指到头,只写
"a" 打开,指向文件尾,在已存在文件中追加
"rb" 打开一个二进制文件,只读
"wb" 打开一个二进制文件,只写
"ab" 打开一个二进制文件,进行追加
"r+" 以读/写方式打开一个已存在的文件
"w+" 以读/写方式建立一个新的文本文件
"a+" 以读/写方式打开一个文件文件进行追加
"rb+" 以读/写方式打开一个二进制文件
"wb+" 以读/写方式建立一个新的二进制文件
"ab+" 以读/写方式打开一个二进制文件进行追加
int fclose(FILE *stream);
当用fopen()成功的打开一个文件时,该函数将返回一个FILE指针,如果文件打开失败,将返回一个NULL指针。如想打开test文件,进行写:
FILE *fp;
if((fp=fopen("test","w"))==NULL)
{
printf("File cannot be opened\n");
exit();
}
else
printf("File opened for writing\n");
fclose(fp);
3 非标准文件的读写
这类函数最早用于UNIX操作系统,ANSI标准未定义,但有时也经常用到。
1).文件的打开和关闭
open()函数的作用是打开文件,其调用格式为:int open(char *filename, int 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 fd);
该函数关闭文件描述字fd相连的文件。
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()相同
4 标准文件操作API
1) fgetc fputc 按照字符读写文件
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
void main01_fputc()
{
int i = 0;
FILE *fp = NULL;
//char *filename = "c:\\1.txt";
char *filename2 = "c:/2.txt"; // 统一的用45度
char a[27]= "abcdefghijklmn";
fp = fopen(filename2, "r+");
if (fp == NULL)
{
printf("func fopen() err:%d \n");
return;
}
printf("打开成功\n");
for (i=0; i<strlen(a); i++)
{
fputc(a[i], fp);
}
fclose(fp);
return ;
}
void main02_fgetc()
{
int i = 0;
FILE *fp = NULL;
//char *filename = "c:\\1.txt";
char *filename2 = "c:/2.txt"; // 统一的用45度
char a[27]= "abcdefghijklmn";
fp = fopen(filename2, "r+"); //读和写方式
if (fp == NULL)
{
printf("func fopen() err:%d \n");
return;
}
printf("打开成功\n");
while (!feof(fp))//检查是否到文件末尾
{
char tempc = fgetc(fp);
printf("%c", tempc);
}
if (fp != NULL)
{
fclose(fp);
}
return ;
}
void main()
{
main01_fputc();//写
main02_fgetc();//读
printf("hello...\n");
system("pause");
return ;
}
2)fputs fgets 按照行(字符串)读写文件(读写配置文件)
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
void main21_fputs()
{
int i = 0;
FILE *fp = NULL;
//char *filename = "c:\\1.txt";
char *filename2 = "c:/22.txt"; // 统一的用45度
char a[27]= "abcdefghijklmn";
//fp = fopen(filename2, "r+"); //读写的方式 打开文件 如果文件不存在 则报错
fp = fopen(filename2, "w+"); //读写的方式 创建文件
if (fp == NULL)
{
printf("func fopen() err:%d \n");
return;
}
printf("打开成功\n");
fputs(a, fp);
fclose(fp);
return ;
}
void main22_fgets()
{
int i = 0;
FILE *fp = NULL;
//char *filename = "c:\\1.txt";
char *filename2 = "c:/22.txt"; // 统一的用45度
//char a[27]= "abcdefghijklmn";
char buf[1024];
fp = fopen(filename2, "r+"); //读和写方式
if (fp == NULL)
{
printf("func fopen() err:%d \n");
return;
}
printf("打开成功\n");
//1 //C 函数库 会 一行一行的copy数据 到buf指针所指的内存空间中 并且变成C风格的字符串
//2 把\n也copy到我们的buf中
//3 内存打包 (把内存首地址 + 内存的长度)
while (!feof(fp))
{
//_Check_return_opt_ _CRTIMP char * __cdecl fgets(_Out_z_cap_(_MaxCount) char * _Buf, _In_ int _MaxCount, _Inout_ FILE * _File);
char *p = fgets(buf, 1024, fp); //C 函数库 会 一行一行的copy数据 到buf指针所指的内存空间中 并且变成C风格的字符串
if (p == NULL)
{
goto End;
}
printf("%s", buf);
}
End:
if (fp != NULL)
{
fclose(fp);
}
return ;
}
void main()
{
//main21_fputs();
main22_fgets();
printf("hello...\n");
system("pause");
return ;
}
3)fread fwirte 按照块读写文件(大数据块迁移)
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
//直接把内存数据 写入到 文件中
typedef struct Teacher
{
char name[64];
int age ;
}Teacher;
void main_fwrite()
{
int i = 0;
FILE *fp = NULL;
char *fileName = "c:/3.data";
Teacher tArray[3];
int myN = 0;
for (i=0; i<3; i++)
{
sprintf(tArray[i].name, "%d%d%d", i+1, i+1, i+1);
tArray[i].age = i + 31;
}
fp = fopen(fileName, "wb");
if (fp == NULL)
{
printf("建立文件失败\n");
return ;
}
for (i=0; i<3; i++)
{
//_Check_return_opt_ _CRTIMP size_t __cdecl
// fwrite(_In_count_x_(_Size*_Count) const void * _Str, _In_ size_t _Size, _In_ size_t _Count, _Inout_ FILE * _File);
//函数参数
//_Str : 从内存块的开始
//_Size //内存打包技术
//_Count 写多少次
//_File : 写入到 文件指针 所指向的文件中
//函数的返回值
myN = fwrite( &tArray[i],sizeof(Teacher) , 1, fp);
//myN 判断 有没有写满 磁盘
}
if (fp != NULL)
{
fclose(fp);
}
}
void main_fread()
{
int i = 0;
FILE *fp = NULL;
char *fileName = "c:/3.data";
Teacher tArray[3];
int myN = 0;
fp = fopen(fileName, "r+b");
if (fp == NULL)
{
printf("建立文件失败\n");
return ;
}
for (i=0; i<3; i++)
{
//_Check_return_opt_ _CRTIMP size_t __cdecl
// fread(_Out_bytecap_x_(_ElementSize*_Count) void * _DstBuf, _In_ size_t _ElementSize, _In_ size_t _Count, _Inout_ FILE * _File);
myN = fread(&tArray[i], sizeof(Teacher), 1, fp);
}
for (i=0; i<3; i++)
{
//sprintf(tArray[i].name, "%d%d%d", i+1, i+1, i+1);
//tArray[i].age = i + 31;
printf("name:%s, age:%d \n", tArray[i].name, tArray[i].age);
}
if (fp != NULL)
{
fclose(fp);
}
}
void main()
{
main_fwrite();
main_fread();
printf("hello...\n");
system("pause");
return ;
}
4)文件控制api
int fseek(FILE *stream, long offset, int fromwhere);函数设置文件指针stream的位置。函数设置文件指针stream的位置。如果执行成功,stream将指向以fromwhere(偏移起始位置:文件头0(SEEK_SET),当前位置1(SEEK_CUR),文件尾2(SEEK_END))为基准,偏移offset(指针偏移量)个字节的位置。如果执行失败(比如offset超过文件自身大小),则不改变stream指向的位置。
fseek函数和lseek函数类似,但lseek返回的是一个off_t数值,而fseek返回的是一个整型。
long ftell(FILE *stream);用于得到文件位置指针当前位置相对于文件首的偏移字节数。 利用函数 ftell() 也能方便地知道一个文件的长。
如以下语句序列: fseek(fp, 0L,SEEK_END); len =ftell(fp);
5) 清除文件缓冲区函数:int fflush(FILE *stream);
fflush()函数将清除由stream指向的文件缓冲区里的内容,常用于写完一些数据后,立即用该函数清除缓冲区,以免误操作时,破坏原来的数据。
6)设置文件缓冲区函数
void setbuf(FILE *stream,char *buf);
void setvbuf(FILE *stream,char *buf,int type,unsigned size);