C:关于如何从归档文件中提取文件的理论

x6492ojm  于 2022-12-03  发布在  其他
关注(0)|答案(5)|浏览(154)

在C语言中,我创建了一个程序,它可以通过命令行将多个文件归档到一个归档文件中。

$echo 'file1/2' > file1/2.txt
$./archive file1.txt file2.txt arhivedfile
$cat archivedfile 
file1
file2

我如何创建一个进程,以便在我的存档文件中:

header
file1
end
header
file2
end

它们都是一个接一个地存储在存档文件中。我知道也许需要一个头文件(包含文件名,文件名的大小,文件的开始和结束)来提取这些文件回到原来的形式,但我该如何去做呢?
我不知道从哪里开始,如何开始。
请有人能帮助我在一些逻辑,如何处理提取文件回出存档文件。

hgncfbus

hgncfbus1#

正如前面提到的,从算法开始,你已经了解了大部分的细节。
您可以采取以下几种方法:
1.随机存取档案。
1.顺序访问归档。

随机存取归档

要使其正常工作,标头需要充当索引(就像图书馆的卡片索引),指示:(a)在哪里找到每个文件的开始;和(B)每个文件的长度。写入存档文件的算法可能如下所示:
1.从命令行获取所有文件的列表。
1.创建一个结构来保存每个文件的 meta数据:名称(255个字符)、大小(64位整型)、日期和时间以及权限。
1.对于每个文件,获取其统计信息。
1.将每个文件的统计信息存储在一个结构数组中。
1.打开归档文件进行写入。
1.编写标头结构。
1.对于每个文件,将其内容附加到归档文件。
1.关闭存档文件。
(The标头可能也必须包含文件数。)
接下来,解压缩文件的算法:
1.从命令行获取存档文件。
1.获取要提取的文件名,也可以从命令行获取。
1.为结构创建内存以读取有关每个文件的 meta数据。
1.从归档文件中读取所有 meta数据。
1.在 meta数据列表中搜索要提取的文件名。
1.计算匹配文件名开头在归档文件中的偏移量。
1.查找偏移量。
1.读取文件内容并将其写入新文件。
1.关闭新档案。
1.关闭归档。

顺序访问

这样比较容易,你可以自己做:仔细思考这些步骤。

关于编程

我们很容易陷入“如何”工作的细节中。我建议你退一步--这是你的老师应该在课堂上讨论的--试着从编码之上的层次来思考这个问题,因为:

  • 您创建算法将与语言无关;
  • 在编写代码之前修复算法中的错误是微不足道的;
  • 您将更好地了解在编码之前需要做什么;
  • 实施解决方案所需的时间更短;
  • 您可以确定可以并行实施的领域;
  • 您将提前看到任何潜在的障碍;和
  • 你很快就会走上管理岗位。- )
uubf1zoe

uubf1zoe2#

我认为文件头需要包含识别文件所需的信息以及文件在归档中的大小a-例如,文件名、原始目录以及以行或字节表示的大小,这取决于哪一个在您的上下文中更有用。(创建文件头并附加文件数据),从归档文件中提取文件(跟踪标题,直到找到正确的条目,并将数据从存档复制到单独的文件),然后删除文件(开始阅读存档,将除要删除的条目之外的所有条目的数据复制到新文件,然后删除旧存档并将新存档重命名为旧名称)。
分享和享受。

hc2pp10m

hc2pp10m3#

一种方法是模仿ZIP格式:http://en.wikipedia.org/wiki/ZIP_file_format
它在文件末尾使用一个目录结构,其中包含指向归档中文件偏移量的指针。这种结构的最大好处是,您可以找到给定的文件,而不必读取整个归档--只要您知道目录的开头,并能够随机访问该文件。
另一种是TAR文件格式:http://en.wikipedia.org/wiki/Tar_file_format
这是为流媒体(“磁带存档”)设计的,因此每个条目都包含自己的元数据。您必须扫描整个文件以找到一个条目,但通常的用例是打包/解包整个目录树,所以这并不是什么太坏的损失。

pgccezyw

pgccezyw4#

以流的方式进行,比如tar,可能是最简单的实现。首先,写出一个幻数,这样你就可以识别出这是你的存档格式。(下)(这是stat手册页的man语法,第2节)来获取要存档的文件的大小。你可能会想保留一些有趣的信息。
以tag=value的方式写出您需要的信息,每行一个。例如:

FileName=file1.txt
FileSize=10
FileDir=./blah/blah
FilePerms=0700

用两个换行符结束头,这样你就知道什么时候开始向磁盘推送FileSize字节。你不需要头的开头标记,因为你知道要写出的文件大小,所以你知道什么时候开始再次解析头。
我建议您使用文本格式的头信息,因为这样您就不必担心字节排序等问题,而如果您将原始二进制结构体写入磁盘,则需要担心这些问题。
阅读归档文件时,逐个解析文件头行,并填充一个本地结构体来保存这些信息。然后将文件写到磁盘,并根据提取的文件头信息设置需要更新的文件属性。
希望能帮上忙祝你好运。

deyfvvtc

deyfvvtc5#

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

typedef struct{
    int size;
    char name[20];
}Header;

void packfiles(char* archive_file, int numfiles, char** filenames){
    FILE* fp = fopen(archive_file, "wb");
    if(!fp){
        perror("Error opening archive file");
        exit(1);
    }

    for(int i = 0; i < numfiles; i++){
        FILE* infile = fopen(filenames[i], "rb");
        if(!infile){
            perror("Error opening input file");
            exit(1);
        }

        //Get file size
        fseek(infile, 0, SEEK_END);
        int fsize = ftell(infile);
        rewind(infile);

        //Create header
        Header header;
        header.size = fsize;
        strncpy(header.name, filenames[i], 20);

        //Write header and file content to archive
        fwrite(&header, sizeof(Header), 1, fp);
        for(int j = 0; j < fsize; j++){
            fputc(fgetc(infile), fp);
        }

        //Add padding if necessary
        if(fsize % 4 != 0){
            for(int j = 0; j < 4-(fsize % 4); j++){
                fputc(0, fp);
            }
        }

        fclose(infile);
    }
fclose(fp);
}

void unpackfiles(char* archive_file){
    FILE* fp = fopen(archive_file, "rb");
    if(!fp){
        perror("Error opening archive file");
        exit(1);
    }

    while(1){
        //Read header
        Header header;
        int read = fread(&header, sizeof(Header), 1, fp);
        if(read == 0){
            //EOF
            break;
        }
        else if(read != 1){
            perror("Error reading header");
            exit(1);
        }

        //Create output file
        FILE* outfile = fopen(header.name, "wb");
        if(!outfile){
            perror("Error creating output file");
            exit(1);
        }

        //Write file content to output file
        for(int i = 0; i < header.size; i++){
            fputc(fgetc(fp), outfile);
        }

        //Skip padding
        fseek(fp, 4-(header.size % 4), SEEK_CUR);

        fclose(outfile);
    }

    fclose(fp);
}

int main(int argc, char** argv){
    if(argc < 3){
        fprintf(stderr, "Usage: %s <archive_file> <file1> [<file2>...]\n", argv[0]);
        exit(1);
    }

    packfiles(argv[1], argc-2, argv+2);
    unpackfiles(argv[1]);

    return 0;
}

相关问题