以字符串的形式读写文件
fgets()读字符串函数
定义形式
用来从指定的文件中读取一个字符串(仅能读取一行字符),并保存到字符数组中。
char *fgets(char *str,int n, FILE *fp); //str为存储的字符数组,n为读取的字符数量
读取成功时,返回字符数组的首地址,即**str**
的首地址;读取失败时,返回**NULL**
。如果开始读取时,文件内部指针已经指向了文件末尾,那么将读取不到字符,返回**NULL**
。
读取到的字符串中,末尾包含了**'\0'**
结束符,即实际读取到的字符为**n-1**
个。
用法
在读取**n-1**
个字符之前,如果出现了换行,或者读到了文件末尾,读取结束。
/* 一行一行地读取文件 */
#include <stdio.h>
#include <stdlib.h>
#define N 100
int main(void)
{
FILE *fp;
char str[N + 1];
//判断文件打开是否失败
if((fp = fopen("D:\\demo.txt","rt")) == NULL)
{
puts("Fail to open file!\n");
exit(0);
}
//连续读取多个字符
while((str, N, fp) != NULL)
{
printf("%s",str);
}
fclose(fp);
return 0;
}
fputs()写字符串函数
定义形式
用来向指定的文件写入一个字符串。
int fputs(char *str, FILE *fp); //str为待写入的字符串
用法
/* 向文件中追加一个字符串 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
FILE *fp;
char str[102] = {0};
char strTemp[100];
//判断文件打开是否失败
if((fp = fopen("D:\\demo.txt","rt")) == NULL)
{
puts("Fail to open file!\n");
exit(0);
}
printf("Input a string: ");
gets(strTemp);
strcat(str,"\n");
strcat(str, strTemp); //字符串拼接
fputs(str, fp); //写入字符串
fclose(fp);
return 0;
}
以数据块的形式读写文件
Windows系统下,使用**fread()**
函数和**fwrite()**
函数时,应以二进制的形式打开。
fread()函数和fwrite()函数
定义形式
用来从指定文件中读写块数据。所谓块数据,可以是若干个字节的数据,可以是一个字符,也可以是一个字符串、多行数据,没有明确的限制。
/* fread()函数 */
size_t fread(void *ptr,size_t size, size_t count, FILE *fp);
/* fwrite()函数 */
size_t fwrite(void *ptr,size_t size, size_t count, FILE *fp);
其中,
1. ptr:为用来存放数据的内存区块的指针,可以是数组、变量或结构体等;
2. size:表示每个数据块的字节数;
3. count:表示要读写的数据块的块数;
4. fp:表示文件指针;
5. 理论上,每次读写size*count个字节的数据。
- 读取成功时,返回读取的块数,即
count
; - 如果返回值小于
count
:
define N 5
int main(){ //从键盘输入的数据放入a,从文件读取的数据放入b int a[N], b[N]; int i, size = sizeof(int); FILE *fp; if( (fp=fopen(“D:\demo.txt”, “rb+”)) == NULL ){ //以二进制方式打开 puts(“Fail to open file!”); exit(0); }
//从键盘输入数据 并保存到数组a
for(i=0; i<N; i++){
scanf("%d", &a[i]);
}
//将数组a的内容写入到文件
fwrite(a, size, N, fp);
//将文件中的位置指针重新定位到文件开头
rewind(fp);
//从文件读取内容并保存到数组b
fread(b, size, N, fp);
//在屏幕上显示数组b的内容
for(i=0; i<N; i++){
printf("%d ", b[i]);
}
printf("\n");
fclose(fp);
return 0;
}
<a name="cdukH"></a>
#### 示例2
```c
/* 从键盘输入两个学生数据,写入一个文件中,再读出这两个学生的数据 */
#include<stdio.h>
#include <stdlib.h>
#define N 2
struct stu{
char name[10]; //姓名
int num; //学号
int age; //年龄
float score; //成绩
}boya[N], boyb[N], *pa, *pb;
int main(){
FILE *fp;
int i;
pa = boya;
pb = boyb;
if( (fp=fopen("d:\\demo.txt", "wb+")) == NULL ){
puts("Fail to open file!");
exit(0);
}
//从键盘输入数据
printf("Input data:\n");
for(i=0; i<N; i++,pa++){
scanf("%s %d %d %f",pa->name, &pa->num,&pa->age, &pa->score);
}
//将数组 boya 的数据写入文件
fwrite(boya, sizeof(struct stu), N, fp);
//将文件指针重置到文件开头
rewind(fp);
//从文件读取数据并保存到数据 boyb
fread(boyb, sizeof(struct stu), N, fp);
//输出数组 boyb 中的数据
for(i=0; i<N; i++,pb++){
printf("%s %d %d %f\n", pb->name, pb->num, pb->age, pb->score);
}
fclose(fp);
return 0;
}
格式化读写文件
fscanf()函数fprintf()函数
定义形式
fscanf()函数fprintf()函数与scanf()函数和printf()函数功能相似,都是格式化读写函数,但前者的读写对象是是磁盘文件,而不是键盘和显示器。
//fscanf()定义(读取文件):
int fscanf(FILE *fp, char *format, ...); //format为格式控制字符串
//fprintf()定义(写入文件):
int fprintf(FILE *fp, char *format, ...);
用法
/* 用 fscanf() 和 fprintf() 函数来完成对学生信息的读写 */
#include <stdio.h>
#include <stdlib.h>
#define N 2
struct stu
{
char name[10];
int num;
int age;
float score;
};
int main(void)
{
struct stu boya[N],boyb[N],*pa,*pb;
FILE *fp;
pa = boya;
pb = boyb;
//判断文件是否打开失败
if((fp = fopen("D:\\demo.txt","wt+")) == NULL)
{
puts("Fail to open file!\n");
exit(0);
}
//输入数据----boya
printf("Input data:\n");
for(int i = 0; i < N; i++,pa++)
{
scanf("%s %d %d %f", pa->name, &pa->num, &pa->age, &pa->score);
}
pa = boya;
//将boya的数据写入文件
for(int i = 0; i < N;i++,pa++)
{
fprintf(fp,"%s %d %d %f\n", pa->name, pa->num, pa->age, pa->score);
}
//重置文件指针
rewind(fp);
//输入数据----boyb
for(i = 0; i < N; i++,pb++){
fscanf(fp, "%s %d %d %f\n", pb->name, &pb->num, &pb->age, &pb->score);
}
pb = boyb;
//将boyb的数据写入文件
for(i=0; i<N; i++,pb++)
{
printf("%s %d %d %f\n", pb->name, pb->num, pb->age, pb->score);
}
fcolse(fp);
return 0;
}
随机读写文件
通过移动文件内部的位置指针,再进行读写的方式,称之为随机读写。即从文件的任意位置开始读写。
实现随机读写的关键,是要按要求移动位置指针,这称为文件的定位。
文件定位函数rewind()和fseek()
定义形式
rewind()函数
**rewind()**
函数用来将位置指针移动到文件开头。
void rewind(FILE *fp);
fseek()函数
**fseek()**
函数用来将位置指针移动到任意位置。
int fseek(FILE *fp, long offset, int origin);
其中,
1. offset为偏移量,也就是要移动的字节数。offset为正时,向后移动,offset为负时,向前移动;
2. origin为起始位置,也就是从何处开始计算偏移量。
C语言规定的起始位置有三种,分别为文件开头、当前位置和文件末尾。
起始点 | 常量名 | 常量值 |
---|---|---|
文件开头 | SEEK_SET | 0 |
当前位置 | SEEK_CUR | 1 |
文件末尾 | SEEK_END | 2 |
**fseek()**
函数一般用于二进制文件,在文本文件中,由于要进行转换,计算的位置有时会出错。
用法
在移动位置指针后,就可以用任一种读写函数进行读写了。由于是二进制文件,通常使用**fread()**
函数和**fwrite()**
函数进行读写。
/* 从键盘输入三组学生信息,保存到文件中,然后读取第二个学生的信息 */
#include <stdio.h>
#include <stdlib.h>
#define N 3
struct stu
{
char name[10];
int num;
int age;
float score;
};
int main(void)
{
struct stu boys[N], boy, *pboys;
FILE *fp;
pboys = boys;
//判断文件打开是否失败
if ((fp = fopen("D:\\demo.txt", "wb+")) == NULL)
{
puts("Fail to open file!\n");
exit(0);
}
printf("Input data:\n");
// 记录学生信息
for (int i = 0; i < N; i++, pboys++)
{
scanf("%s %d %d %f", pboys->name, &pboys->num, &pboys->age, &pboys->score);
}
fwrite(boys, sizeof(struct stu), N, fp); //将学生信息写入文件
fseek(fp, sizeof(struct stu), SEEK_SET); //移动向后一个结构体空间的位置指针
fread(&boy, sizeof(struct stu), 1, fp); //读第二个学生信息
printf("%s %d %d %f", boy.name, boy.num, boy.age, boy.score); //打印学生信息
fclose(fp); //关闭文件
return 0;
}
C语言实现文件复制功能
主要思路
开辟一个缓冲区,不断从原文件中读取内容到缓冲区,每读取完一次,就将缓冲区中的内容写入到新建的文件,直到把原文件的内容读取完。需要注意的是,**fopen()**
一定要以二进制的形式打开文件,否则系统会对文件进行一些处理,可能会导致复制后的文件出错。
实现
/* 实现复制文件功能 */
#include <stdio.h>
#include <stdlib.h>
#define BUF_LEN 1024 * 4 //4k对齐空间
int copyFile(char *fileRead, char *fileWrite);
int main(void)
{
char fileRead[100]; //要复制的文件名
char fileWrite[100]; //复制后的文件名
// 获取用户输入
printf("要复制的文件:");
scanf("%s", fileRead);
printf("将文件复制到:");
scanf("%s", fileWrite);
// 进行复制操作
if (copyFile(fileRead, fileWrite))
{
printf("恭喜你,文件复制成功!\n");
}
else
{
printf("文件复制失败!\n");
}
return 0;
}
/**
* 文件复制函数
* @param fileRead 要复制的文件的路径
* @param fileWrite 复制后文件的保存路径
* @return int 1: 复制成功;2: 复制失败
**/
int copyFile(char *fileRead, char *fileWrite)
{
FILE *fpRead; //需要读取复制的文件指针
FILE *fpWrite; //需要写入的文件的指针
char *buffer = (char *)malloc(BUF_LEN); //开辟动态缓冲区
int readCount; //实际读取到的字节数
// 判断打开需要读写的文件是否失败
if (((fpRead = fopen(fileRead, "rb")) == NULL) || ((fpRead = fopen(fileWrite, "wb")) == NULL))
{
printf("Cannot open file, press any key to exit!\n");
getchar();
exit(1);
}
// 复制文件
while ((readCount = fread(buffer, 1, BUF_LEN, fpRead)) > 0)
{
fwrite(buffer, readCount, 1, fpWrite);
}
free(buffer); //释放动态内存
fclose(fpRead); //关闭文件
fclose(fpWrite); //关闭文件
return 1;
}
获取文件大小
C语言没有提供获取文件大小的函数,只能通过自己编写函数实现。
ftell()函数
定义形式
用来获取文件内部位置指针距离文件开头的字节数。
long int ftell(FILE *fp);
**fp**
要以二进制方式打开。如果以文本方式打开,函数的返回值可能没有意义。
用法
/* 实现获取文件大小功能 */
#include <stdio.h>
#include <stdlib.h>
long fsize(FILE *fp);
int main(void)
{
long size = 0;
FILE *fp = NULL;
char filename[30] = "D:\\1.mp4";
if ((fp = fopen(filename, "rb")) == NULL)
{ //以二进制方式打开文件
printf("Failed to open %s...", filename);
getch();
exit(EXIT_SUCCESS);
}
printf("%ld\n", fsize(fp));
return 0;
}
long fsize(FILE *fp)
{
long n = 0; //
fpos_t fpos; //记录当前指针位置
fgetpos(fp, &fpos); //读取当前指针位置
fseek(fp, 0, SEEK_END); //移动位置指针到文件末尾
n = ftell(fp); //获取文件长度大小
fsetpos(fp, &fpos); //恢复之前的指针位置
return n;
}
插入、删除和更改文件内容
文件类型
- 顺序文件(最常见的文件类型,文件内容按从头到尾的顺序依次存储在磁盘);
- 索引文件;
- 散列文件。
C语言没有提供插入、删除和更改文件内容的函数,只能通过自己编写函数实现。
文件复制函数
在数据的插入删除过程中,需要多次复制文件内容,我们有必要将该功能实现为一个函数。
/**
* 文件复制函数
* @param fSource 要复制的原文件
* @param offsetSource 原文件的位置偏移(相对文件开头),也就是从哪里开始复制
* @param len 要复制的内容长度,小于0表示复制offsetSource后边的所有内容
* @param fTarget 目标文件,也就是将文件复制到哪里
* @param offsetTarget 目标文件的位置偏移,也就是复制到目标文件的什么位置
* @return 成功复制的字节数
**/
long fcopy(FILE *fSource, long offsetSource, long len, FILE *fTarget, long offsetTarget){
int bufferLen = 1024*4; // 缓冲区长度
char *buffer = (char*)malloc(bufferLen); // 开辟缓存
int readCount; // 每次调用fread()读取的字节数
long nBytes = 0; //总共复制了多少个字节
int n = 0; //需要调用多少次fread()函数
int i; //循环控制变量
fseek(fSource, offsetSource, SEEK_SET);
fseek(fTarget, offsetTarget, SEEK_SET);
if(len<0){ //复制所有内容
while( (readCount=fread(buffer, 1, bufferLen, fSource)) > 0 ){
nBytes += readCount;
fwrite(buffer, readCount, 1, fTarget);
}
}else{ //复制len个字节的内容
n = (int)ceil((double)((double)len/bufferLen));
for(i=1; i<=n; i++){
if(len-nBytes < bufferLen){ bufferLen = len-nBytes; }
readCount = fread(buffer, 1, bufferLen, fSource);
fwrite(buffer, readCount, 1, fTarget);
nBytes += readCount;
}
}
fflush(fTarget);
free(buffer);
return nBytes;
}
插入数据
主要思路
- 创建一个临时文件,将插入位置后面的内容复制到临时文件;
- 将原文件的内部位置指针移动到插入位置,写入插入内容;
-
实现
/**
* 向文件中插入内容
* @param fp 要插入内容的文件
* @param buffer 缓冲区,也就是要插入的内容
* @param offset 偏移量(相对文件开头),也就是从哪里开始插入
* @param len 要插入的内容长度
* @return 成功插入的字节数
**/
int finsert(FILE *fp, long offset, void *buffer, int len){
long fileSize = fsize(fp);
FILE *fpTemp; //临时文件
if(offset>fileSize || offset<0 || len<0){ //插入错误
return -1;
}
if(offset == fileSize){ //在文件末尾插入
fseek(fp, offset, SEEK_SET);
if(!fwrite(buffer, len, 1, fp)){
return -1;
}
}
if(offset < fileSize){ //从开头或者中间位置插入
fpTemp = tmpfile();
fcopy(fp, 0, offset, fpTemp, 0);
fwrite(buffer, len, 1, fpTemp);
fcopy(fp, offset, -1, fpTemp, offset+len);
freopen(FILENAME, "wb+", fp );
fcopy(fpTemp, 0, -1, fp, 0);
fclose(fpTemp);
}
return 0;
}
删除数据
主要思路
创建一个临时文件,将删除位置前面的所有内容复制到临时文件,再将删除位置后面的所有内容复制到临时文件;
- 将原文件删除,并创建一个新的同名文件;
-
实现
int fdelete(FILE *fp, long offset, int len){
long fileSize = getFileSize(fp);
FILE *fpTemp;
if(offset>fileSize || offset<0 || len<0){ //错误
return -1;
}
fpTemp = tmpfile();
fcopy(fp, 0, offset, fpTemp, 0); //将前offset字节的数据复制到临时文件
fcopy(fp, offset+len, -1, fpTemp, offset); //将offset+len之后的所有内容都复制到临时文件
freopen(FILENAME, "wb+", fp ); //重新打开文件
fcopy(fpTemp, 0, -1, fp, 0);
fclose(fpTemp);
return 0;
}
更改文件内容
主要思路
修改数据时,如果新数据和旧数据长度相同,那么设置好内部指针,直接写入即可;
- 如果新数据比旧数据长,相当于增加新内容,思路和插入数据类似;
- 如果新数据比旧数据短,相当于减少内容,思路和删除数据类似。
实现
// 略。