在C编程中提取存档文件

时间:2013-10-21 05:18:33

标签: c extract archive

我想在这里扩展这个问题:

C theory on how to extract files from an archived file

它讨论如何获取已归档的文件并将其解压缩并将其返回到文件表单,而不使用命令ar -x

答案中的算法说明了以下几个步骤:

  1. 从命令行获取要提取的文件名。
  2. 为结构创建内存以读取有关每个文件的元数据。
  3. 从存档文件中读取所有元数据。
  4. 有人可以给我一些关于在这些步骤中使用的功能的提示吗?我真的不知道它在第2步中谈论的是什么结构。

1 个答案:

答案 0 :(得分:0)

给出了归档和提取细节+代码的实现。要归档文件,请使用这种最简单的归档文件格式。

HEADER | CONTENTS

标题包含有关文件的元数据,包括标题的大小,不包括标题大小数据,文件名和由/分隔的相应文件大小。我使用/作为分隔符,因为它们不会出现在Linux简单文件名中,除非它是路径名。如果您打算包含路径名,则可以使用其他分隔符。

Body包含一个接一个附加的每个文件的内容。

以下是我的归档文件的格式。


文件大小/文件1名称/文件1大小/文件2名称/文件2大小/身体

我使用以下C结构来收集有关归档和提取的单个文件的元数据。

struct mdata
{
   char name[255];
   FILE *fp;
   int size;
   int nsize;
   int ssize;
   struct mdata *next;
};

我使用链表来包含文件元数据列表。

存档代码:./ archive file1 file2 archive1

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BSIZE 2048


struct mdata
{
    char name[255];
    FILE *fp;
    int size;
    int nsize;
    int ssize;
    struct mdata *next;
};

struct mdata *mhead = NULL, *current = NULL;

int getsize(FILE *fp)
{
    int size = 0;
    fseek(fp, 0L, SEEK_END);      
    size  = ftell(fp);
    fseek(fp, 0L, SEEK_SET);   
    return size;
}

int add(char *name)
{    
    FILE *fp;
    char ntemp[255];
    struct mdata *newm;
    newm = (struct mdata *)malloc(sizeof(struct mdata));
    strcpy(newm->name, name);    
    fp = fopen(name, "r+");  
    newm->fp = fp;
    newm->size = getsize(fp);  
    newm->nsize = strlen(name);
    sprintf(ntemp, "%d", newm->size);
    newm->ssize = strlen(ntemp);
    newm->next = NULL;
    printf("File %s is being processed...\n", name);
    if(mhead == NULL) 
    {
        mhead = newm;
        current = newm;
    }
    else
    {
        current->next = newm;
        current = newm;
    }
}

int preproc(int argc, char** argv)
{
    int i;

    for(i = 1; i <= argc-2; i++)  
    {   
        add(argv[i]);  
    }    
}

int main(int argc, char** argv) 
{
    char block[BSIZE];
    char stsize[5];
    char shsize[100];
    int rsize = 0;
    int tnsize = 0, tssize = 0, hsize = 0, scount = 0;
    struct mdata *ptr;
    FILE *fpar, *fp;

    //CREATE HEADER
    printf("Pre-processing the files to collect meta data...\n");
    preproc(argc, argv);
    printf("Pre-processing completed.\n");
    printf("Compiling header information.\n");
    fpar = fopen(argv[argc-1], "w+");
    ptr = mhead;
    while(ptr != NULL)
    {
        tnsize += ptr->nsize;        
        tssize += ptr->ssize;
        ptr = ptr->next;
        scount +=2;
    }
    hsize = tnsize+tssize+scount+1; 
    printf("Total length of file names is %d\n", tnsize);
    printf("Total length of file sizes is %d\n", tssize);
    printf("Total size of header except file size is %d.\n", hsize);
    sprintf(shsize, "%d/", hsize); //10 bytes of header size
    fwrite(shsize, 1, strlen(shsize), fpar);
    ptr = mhead;
    while(ptr != NULL)
    {
        fwrite(ptr->name, 1, ptr->nsize, fpar);   
        fwrite("/", 1, 1, fpar);
        sprintf(stsize, "%d", ptr->size);
        fwrite(stsize, 1, ptr->ssize, fpar);  
        fwrite("/", 1, 1, fpar);
        ptr = ptr->next;
    }    
    printf("The header created and written to archieve file.\n");
    //CREATE BODY
    ptr = mhead;
    while(ptr != NULL)
    {
        fp = ptr->fp;
        while(rsize = fread(block, 1, sizeof(block), fp))
        {
            fwrite(block, 1, rsize, fpar);
        }
        ptr = ptr->next;
    }   
    printf("Contents of all files written to archieve file.\n");
    fclose(fpar);  
    return 0;
}

提取代码:./提取存档

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BSIZE 2048


struct mdata
{
    char name[255];
    FILE *fp;
    int size;
    int nsize;
    int ssize;
    struct mdata *next;
};

struct mdata *mhead = NULL, *current = NULL;

int min(int x, int y)
{
    if(x < y) return x;
    else return y;
}
int getsize(FILE *fp)
{
    int size = 0;
    fseek(fp, 0L, SEEK_END);      
    size  = ftell(fp);
    fseek(fp, 0L, SEEK_SET);   
    return size;
}

int add(char *name, int size)
{    
    char ntemp[255];
    struct mdata *newm;
    newm = (struct mdata *)malloc(sizeof(struct mdata));
    strcpy(newm->name, name);    
    newm->size = size;
    newm->nsize = strlen(name);
    sprintf(ntemp, "%d", newm->size);
    newm->ssize = strlen(ntemp);
    newm->next = NULL;
    printf("File %s is being processed...\n", name);
    if(mhead == NULL) 
    {
        mhead = newm;
        current = newm;
    }
    else
    {
        current->next = newm;
        current = newm;
    }
}

int readh(FILE *fp1)
{
    int i = 0, j= 1 ;    
    int hsize = 0, size = 0;
    int byte;
    char shsize[50]; 
    char name[255];
    char ssize[50];
    while((byte = fgetc(fp1))!='/')
    {
        shsize[i] = (char)byte;
        i++;
    }
    shsize[i] = '\0';
    hsize = atoi(shsize);
    hsize += strlen(shsize);
    printf("The total size of header is %d.\n", hsize);
    printf("Contents starts at %dth byte.\n", hsize);
    //COLLECT NAMES AND SIZES
    j = strlen(shsize)+1;
    while(j <= hsize-1)
    {
        i = 0;
        while((byte = fgetc(fp1))!='/')
        {
            name[i++] = byte;
            j++;
        }
        j++;
        name[i] = '\0';
        i = 0;
        while((byte = fgetc(fp1))!='/')
        {
            ssize[i++] = byte;
            j++;
        }     
        j++;
        ssize[i] = '\0';
        size = atoi(ssize);
        printf("File '%s' with size %d added to list.\n", name, size);
        add(name, size);
        printf("File '%s' processing completed.\n", name);
    }
    printf("File meta data collection successfully completed.\n");
}

int main(int argc, char** argv) 
{
    char block[BSIZE];
    char stsize[5];
    char shsize[100];
    int rsize = 0;
    int tnsize = 0, tssize = 0, hsize = 0, scount = 0;
    int totsize = 0;
    int unreadcount = 0;
    struct mdata *ptr;
    FILE *fpar, *fp;

    //COLLECTING HEADER
    printf("Opening file %s...\n", argv[1]);
    fpar = fopen(argv[1], "r+");
    if(fpar == NULL)
    {
        printf("Error opening file %s.\n", argv[1]);
    }
    readh(fpar);
    ptr = mhead;
    lseek(fpar, hsize+1, SEEK_SET);
    while(ptr != NULL)
    {
        totsize = 0;
        printf("Creating file %s...\n", ptr->name);
        fp = fopen(ptr->name, "w+"); 
        printf("Writing %d bytes of %s...\n", ptr->size, ptr->name);
        unreadcount = ptr->size;
        while(unreadcount > 0)
        {
            if(sizeof(block)>= unreadcount)
            {
                rsize = fread(block, 1, unreadcount, fpar);
            }
            else
            {
                rsize = fread(block, 1, sizeof(block), fpar);
            }
            unreadcount -= rsize;
            totsize += rsize;
            fwrite(block, 1, rsize, fp);
        }
        printf("Written %d bytes to file %s.\n", totsize, ptr->name);
        ptr = ptr->next;
    }
    printf("Extraction completed.\n");
    fclose(fpar);  
    return 0;
}