首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C语言 >

资料的合并与分离(FILE*)

2012-07-30 
文件的合并与分离(FILE*)问题:如果你想把一个或多个文件流写入一个文件中,并能实现回放的功能,也就是把之

文件的合并与分离(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读取到一个文件的结尾?

下面附上代码,有点乱。。。。


C/C++ code
#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);  } 






[解决办法]
c区现在这么冷清了么
感觉是不是可以单独存一个文件来保存合并信息
[解决办法]
思路大概正确。
如果要考虑其他因素,比如使合并文件尽量小,比如可以使多进程互斥读写等等,则还有很多优化的空间。
[解决办法]
文件系统?

参考一下暴雪的MPQ
[解决办法]
lz是把索引信息直接写到目标文件了,同意2楼,是否可以单独建一个索引文件。
[解决办法]
先安装WinRAR软件到目录C:\Program Files\WinRAR中,然后:
system("c:\\progra~1\\winrar\\rar.exe a package.rar ...");
system("c:\\progra~1\\winrar\\rar.exe vb package.rar >package.txt");
//然后读文件package.txt的内容
system("c:\\progra~1\\winrar\\rar.exe x package.rar ...");

热点排行