C语言实现目录打包

思路:
如下图,目录文件按指定格式打包到一个文件。
这里写图片描述


#include<stdio.h>
#include<sys/types.h>
#include<dirent.h>
#include<string.h>
#include<sys/stat.h>
#include<unistd.h>

//filename: ./test/file
struct file_info{//用于保存文件名和对应的inode,用于判断是否为硬链接文件
    char filename[100];
    ino_t inode;
}filesave[1024];
void tarfile(const char* filename,FILE* fpOut){//打包文件

    struct stat stat_buf;
    stat(filename,&stat_buf);
    filesave[1024];
    int i;
    static n=0;//记录写入文件的真实数量,不包括硬链接文件
    for(i=0;i<=n;i++){//判断文件是否已写入
        if(filesave[i].inode==stat_buf.st_ino){//判断是硬链接文件
            fprintf(fpOut,"h\n%s\n%s\n",filename,filesave[i].filename);//写入标记h->newname->oldname
            return;
        }
    }

    fprintf(fpOut,"f\n%s\n%d\n",filename,(int)stat_buf.st_size);
    FILE *fpIn=fopen(filename,"r");
    char buf[4096];
    while(1){
        int ret=fread(buf,1,sizeof(buf),fpIn);
        if(ret<=0){
            break;
        }
        fwrite(buf,ret,1,fpOut);
    }
    strcpy(filesave[n].filename,filename);//将新打包的文件写入结构体记录
    filesave[n].inode=stat_buf.st_ino;
    n++;
    fclose(fpIn);
}

//dirname: ./test
int tardir(const char* dirname,FILE* fpOut){//打包目录
    char filepath[1024];
    fprintf(fpOut,"d\n");//d目录标记
    fprintf(fpOut,"%s\n",dirname);//打包的根目录

    DIR* dir=opendir(dirname);//打开文件目录项
    struct dirent* entry=readdir(dir);
    while(entry){
        //./test/file
        sprintf(filepath,"%s/%s",dirname,entry->d_name);//拼凑每个目录项的路径
        if(entry->d_type==DT_REG){//判断是否为文件
            tarfile(filepath,fpOut);//打包文件
        }
        else if(entry->d_type==DT_DIR){//判断是否为目录,若是就继续递归
            if((strcmp(entry->d_name,".")==0)||
                (strcmp(entry->d_name,"..")==0)){//. ..忽略
                entry=readdir(dir);
                continue;
            }
            tardir(filepath,fpOut);
        }
        entry=readdir(dir);
    }
    closedir(dir);  
}

int tar(const char* dirname,const char *outfile){
    FILE* fpOut=fopen(outfile,"w");
    fprintf(fpOut,"xgltar\n");//标记打包文件类型
    fprintf(fpOut,"1.0\n");//版本
    int ret=tardir(dirname,fpOut);//打包目录
    fclose(fpOut);
    return ret;
}

int untarfile(FILE *fin){
    char buf[1024];
    if(fgets(buf,sizeof(buf),fin)==NULL){
        return -1;
    }   
    printf("now utar type=%s",buf);
    if(strcmp(buf,"d\n")==0){//目录标记
        fgets(buf,sizeof(buf),fin);
        buf[strlen(buf)-1]=0;
        mkdir(buf,0777);
        printf("mkdir %s\n",buf);
    }
    else if(strcmp(buf,"f\n")==0){//文件标记
        fgets(buf,sizeof(buf),fin);
        buf[strlen(buf)-1]=0;
        FILE *out=fopen(buf,"w");
        printf("create file %s\n",buf);
        fgets(buf,sizeof(buf),fin);
        int len=atol(buf);
        printf("filelen %s\n",buf);
        while(len>0){
            int readlen=len<sizeof(buf)?len:sizeof(buf);
            int ret=fread(buf,1,readlen,fin);
            fwrite(buf,1,ret,out);
            len-=ret;
        }
        fclose(out);
    }
    else if(strcmp(buf,"h\n")==0){//硬链接文件标记
        fgets(buf,sizeof(buf),fin);//读取链接文件名
        buf[strlen(buf)-1]=0;
        char oldbuf[1024];//被链接的文件名
        fgets(oldbuf,sizeof(oldbuf),fin);
        oldbuf[strlen(oldbuf)-1]=0;
        link(oldbuf,buf);
    }
    return 0;
}
//解包
int untar(const char* tarfile){
    char buf[1024];
    FILE *fin=fopen(tarfile,"r");
    fgets(buf,sizeof(buf),fin);
    if(strcmp(buf,"xgltar\n")!=0){//判断是否为打包文件类型
        printf("unknown file format\n");
        return -1;
    }
    fgets(buf,sizeof(buf),fin);
    if(strcmp(buf,"1.0\n")==0){//判断版本是否正确
        while(1){
            int ret=untarfile(fin);//解包
            if(ret!=0){
                break;
            }
        }
    }else{
        printf("unknown version\n");
        return -1;
    }
    return 0;

}
//./tar -c test tartest
//./tar -u tartest
int main(int argc,char *argv[])
{
    if(argc==1){
        printf("usage:\t./tar -c file1 file2  or ./tar -u file1\n");
        return -1;
    }

    const char *option=argv[1];
    if(strcmp(option,"-c")==0){
        const char* dirname=argv[2];
        const char* outfile=argv[3];
        return tar(dirname,outfile);    //打包
    }else if(strcmp(option,"-u")==0){
        const char* tarfile=argv[2];    
        return untar(tarfile);          //解包 
    }

    printf("option error\n");
    return -1;
}
  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值