文件的合并与分离(FILE*)
问题:如果你想把一个或多个文件流写入一个文件中,并能实现回放的功能,也就是把之前写入的文本数据按照原来的写入方式分离出来,你要怎么写,又怎么分离?
PS:可能好多人已经接触过这类题型,也或者有些参加工作的人遇到过这样类似的面试题,也或者一些才入门的C/C++童鞋们,你们也正在思考这个问题并被困扰着如何下手。
下面我就来说明下我的思路,并附上源码(代码没有封装,只供参考),请大大们指出不足之处,不要喷,如果你们有更好的解决办法,也可以拿出来一起探讨探讨!
Okay...如果你只把一个文本文件读出并写入另一个文件中,ok,什么都不用考虑,fwrite fread直接用就行
但是如果给你两个文本,你难道也那样嘛?如果你不考虑那个回放的功能也就是分离功能的话,你也大可不必
考虑什么,只需当第一个文本文件数据写入结束时,将当前的写入指针比如fpwrite指向末尾就行,fseek就能办到
-->fseek(fpwrite,0,SEEK_END);然后再写入第二个,这样就避免了两个文本写入时被覆盖的情况,初步达到友好
合并的效果,但是问题出现了,你怎么样把这两个文件的内容很完美的从当前的文件中
分离出来再分别保存到两个文件中呢?有些人说,这不好办,我每写入一次文件,在文件末尾做个标记MARK,那么我分离的时候只要每次匹配我的MARK就行了啊!?但是,你的MARK肯定是受限制的吧?万一你的MARK标记的内容正好是你写入的文件里面数据的一部分呢?如果这样,坏了,你分离的肯定是乱七八糟,断断续续,这不坑人嘛!
Then....也许你们还有其他的想法,现在我来说说我的想法。
先就一个文本文件来分析。它包括三个部分,文件名称f_name,文件内容buffer,以及文件存储的字节数f_count
对于文件内容,你可以很轻松的用fread读出来,至于,f_name和f_count,你可以定义一个结构体,来存储文件的
基本信息,包括文本的名字和文本的字节数;
如:
typedef struct _tg_struct
{
char f_name[30];
int savef_count;
}SAVEFILE;//总过30+2+4个字节
前30个字节存储文件名称,后4个字节存储文本内容长度
这样如果你写入一个文件,也就是写入一个 结构体+内容 的格式,如果你再写入一个文件,也是这样,这样的好处,体现在分离文件的时候,比如,你若要分离出第一个文件,只需要fread的时候,取出第一个文件头中的信息,分别匹配名字和按长度读取savef_count次,就可以读到第一个文件的末尾,blablablabla,然后控制下指针位置,
fseek(fpread,sizeof(SAVEFILE)+savef_count,SEEK_SET);这样的话,当前指针的位置就来到了第二个文件的文件头这里
然后,参考第一个文件的读取方式,再分离第二个无非就是copy一下代码(如果不想,封装起来把!)
OK,可能你们还有疑问,怎么样计算文件内容的长度,又怎么样根据savef_count读取到一个文件的结尾?
下面附上代码,有点乱。。。。
#include <stdio.h>#include "string.h"#define NULL 0typedef struct _tg_struct{ char f_name[30]; int savef_count; }SAVEFILE;enum { ERROR_PARAM, ERROR_FILE, SUCCESS,};int SaveFile(const char* fSrc1,const char* fSrc2,const char* fDes );//合并文件夹int ReadFile(char* fDes,const char* fSrc1,const char* fSrc2const ); //分离文件夹int main(){ printf("正在写文件,请稍等....."); SaveFile("c:\\a.txt","c:\\b.txt","c:\\c.txt"); printf("正在读文件,请稍等....."); ReadFile("c:\\c.txt","c:\\d.txt","c:\\e.txt"); getchar(); return 0;}int SaveFile(const char* fSrc1,const char* fSrc2,const char* fDes ){ SAVEFILE savef; FILE* fpWrite,*fpRead; char buffer[1024]; int a = 0; int b = 0; memset(&savef,0,sizeof(SAVEFILE)); fpWrite=fopen(fDes,"wb+");//写入目标文件 strcpy(savef.f_name,fSrc1); fpRead=fopen(fSrc1,"rb");//读源文件1 if(fpWrite==NULL || fpRead==NULL) { return ERROR_PARAM; } fwrite(&savef,1,sizeof(SAVEFILE),fpWrite);//写文件头 此时savef.savef_count=0 while(!feof(fpRead)) { a=0; a=fread(buffer,1,1000,fpRead);//将内容读入到buffer中 printf("a=%d\n",a); savef.savef_count+=a;//累计文件内容的字节数 fwrite(buffer,1,a,fpWrite);//读了再写入内容 } fseek(fpWrite,0,SEEK_SET);//将指针置为文件开始处 fwrite(&savef,1,sizeof(SAVEFILE),fpWrite);//重写文件头 此时savef.savef_count!= 0 printf("savef_count=%d\n",savef.savef_count); fseek(fpWrite,0,SEEK_END);//将文件指针指向文件最后 b=savef.savef_count;//这个留着下次写时有用 fclose(fpRead); memset(&savef,0,sizeof(SAVEFILE));//如果对大文件进行置空的话,是非常耗费CPU的 strcpy(savef.f_name,fSrc2);// printf("file2_name=%s\n",savef.f_name); fpRead=fopen(fSrc2,"rb");//打开第二个文件 fwrite(&savef,1,sizeof(SAVEFILE),fpWrite);//写文件头信息 while(!feof(fpRead)) { a=0; a=fread(buffer,1,1000,fpRead); printf("a=%d\n",a); savef.savef_count+=a; fwrite(buffer,1,a,fpWrite);//读了再写入内容 } fseek(fpWrite,sizeof(SAVEFILE)+b,SEEK_SET); fwrite(&savef,1,sizeof(SAVEFILE),fpWrite); printf("savef_count=%d",savef.savef_count); fclose(fpWrite); fclose(fpRead);}int ReadFile(const char* fSrc,const char* fDes1,const char* fDes2 ){ FILE *p_fwrite;//写 FILE *p_fread; //读 SAVEFILE savef; char buffer[1024]; int a = 0;//字节数 int b = 0;//文件内容所占字节数 int current=0;//保存第一次分离的文件的内容所占的字节数 memset(&savef,0,sizeof(SAVEFILE));//置空结构体 p_fread=fopen(fSrc,"rb");//读写二进制 p_fwrite=fopen(fDes1,"wb+");//写附加 if(p_fwrite == NULL || p_fread == NULL) { printf("File open failed....."); return ERROR_PARAM; } //将p_fread中指向的大小为sizeof(SAVEFILE)的内容读入到结构体savef中 a=fread(&savef,1,sizeof(SAVEFILE),p_fread); //savef包括两个部分,一个30字节的文件头 一个4字节的文件内容字节数 b=savef.savef_count; current=b;//记下 printf("\nThe first file bytes is %d\n",b); if(b > 0) { //如果大于0 存在内容 循环控制读取 while(b >= 1000) { a=0; a=fread(buffer,1,1000,p_fread);//读入buffer保存读取数据 b-=a;//如果b<1000 则跳出循环 然后按照一次b个字节读取 fwrite(buffer,1,a,p_fwrite);//第一次分离文件,写指针指向fDes1 if(b < 1000) break; } if(b < 1000 && b > 0) { a=fread(buffer,1,b,p_fread);//一次读完 fwrite(buffer,1,a,p_fwrite);//一次写完 } }//end first fclose(p_fwrite);//关闭第一次读的文件指针 printf("分离并写入%s成功\n\n",savef.f_name); //第二次读 memset(&savef,0,sizeof(SAVEFILE));//再一次置空,防止数据干扰 p_fwrite=fopen(fDes2,"wb+");//分离第二个文件 fseek(p_fread,sizeof(SAVEFILE)+current,SEEK_SET);//当前读指针指向第二个文件头处 a=fread(&savef,1,sizeof(SAVEFILE),p_fread); printf("\nsave_count=%d\n",savef.savef_count); b=savef.savef_count;//第二个文件内容所占的字节数 //同上面,流程一样 最好封装一下 printf("\nThe first file bytes is %d\n",b); if(b > 0) { while(b <= 1000) { a=0; a=fread(buffer,1,1000,p_fread); b-=a; fwrite(buffer,1,a,p_fwrite); //判断下b的值 if(b < 1000) break;//直接跳出 } if(b > 0 && b < 1000) { a=fread(buffer,1,b,p_fread); //再一次写入剩下不足1000字节的内容 fwrite(buffer,1,a,p_fwrite); } }//end second printf("分离并写入%s成功",savef.f_name); fclose(p_fwrite);//关闭 fclose(p_fread); }