简化版文件封包解包程序
三个部分
文件头
索引表
文件数据
索引表的每个offset记录的是每个诗句相对于数据区起始位置的偏移量
// 简化版文件封包解包程序 #include <stdio.h> #include <string.h> #include <stdlib.h> #include <dirent.h> #include <sys/stat.h> #define PACK_FILE "archive.dat" #define MAX_PATH 256 // 文件头结构 struct FileHeader { int file_count; // 文件数量 long data_start; // 数据区起始位置 }; // 文件索引结构 struct FileIndex { char name[256]; // 文件名 long offset; // 每个文件相对于数据区起始位置的偏移 long size; // 文件大小 }; // 获取文件大小 long get_file_size(FILE *fp) { long size; fseek(fp, 0, SEEK_END); size = ftell(fp); fseek(fp, 0, SEEK_SET); return size; } // 打包函数 void pack_folder(const char *folder) { printf("正在打包文件夹: %s\n", folder); // 打开文件夹 DIR *dir = opendir(folder); if (!dir) { printf("无法打开文件夹\n"); return; } // 收集文件信息 struct dirent *entry; struct FileIndex *indexes = NULL; int file_count = 0; long current_offset = 0; // 第一遍:统计文件 while ((entry = readdir(dir)) != NULL) { if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue; char fullpath[512]; snprintf(fullpath, sizeof(fullpath), "%s/%s", folder, entry->d_name); struct stat st; if (stat(fullpath, &st) == 0 && S_ISREG(st.st_mode)) { file_count++; } } if (file_count == 0) { printf("文件夹为空\n"); closedir(dir); return; } // 分配索引数组 indexes = malloc(file_count * sizeof(struct FileIndex)); if (!indexes) { printf("内存分配失败\n"); closedir(dir); return; } // 第二遍:收集文件信息 rewinddir(dir); int idx = 0; while ((entry = readdir(dir)) != NULL) { if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue; char fullpath[512]; snprintf(fullpath, sizeof(fullpath), "%s/%s", folder, entry->d_name); struct stat st; if (stat(fullpath, &st) == 0 && S_ISREG(st.st_mode)) { // 获取文件大小 FILE *fp = fopen(fullpath, "rb"); if (fp) { strncpy(indexes[idx].name, entry->d_name, 255); indexes[idx].name[255] = '\0'; indexes[idx].offset = current_offset; indexes[idx].size = get_file_size(fp); current_offset += indexes[idx].size; fclose(fp); idx++; } } } closedir(dir); // 创建封包文件 FILE *pack = fopen(PACK_FILE, "wb"); if (!pack) { printf("无法创建封包文件\n"); free(indexes); return; } // 写入文件头 struct FileHeader header; header.file_count = file_count; header.data_start = sizeof(struct FileHeader) + file_count * sizeof(struct FileIndex); fwrite(&header, sizeof(struct FileHeader), 1, pack); // 写入索引表 fwrite(indexes, sizeof(struct FileIndex), file_count, pack); // 写入文件数据 for (int i = 0; i < file_count; i++) { char fullpath[512]; snprintf(fullpath, sizeof(fullpath), "%s/%s", folder, indexes[i].name); FILE *src = fopen(fullpath, "rb"); if (src) { char buffer[4096]; size_t read; while ((read = fread(buffer, 1, sizeof(buffer), src)) > 0) { fwrite(buffer, 1, read, pack); } fclose(src); printf("打包: %s (%ld 字节)\n", indexes[i].name, indexes[i].size); } } fclose(pack); free(indexes); printf("打包完成! 共 %d 个文件\n", file_count); } // 解包函数 void unpack_files(const char *packfile) { printf("正在解包: %s\n", packfile); FILE *pack = fopen(packfile, "rb"); if (!pack) { printf("无法打开封包文件\n"); return; } // 读取文件头 struct FileHeader header; if (fread(&header, sizeof(struct FileHeader), 1, pack) != 1) { printf("读取文件头失败\n"); fclose(pack); return; } printf("文件数量: %d\n", header.file_count); // 读取索引表 struct FileIndex *indexes = malloc(header.file_count * sizeof(struct FileIndex)); if (!indexes) { printf("内存分配失败\n"); fclose(pack); return; } if (fread(indexes, sizeof(struct FileIndex), header.file_count, pack) != header.file_count) { printf("读取索引表失败\n"); free(indexes); fclose(pack); return; } // 定位到数据区 fseek(pack, header.data_start, SEEK_SET); // 解包所有文件 for (int i = 0; i < header.file_count; i++) { printf("解包: %s (%ld 字节)\n", indexes[i].name, indexes[i].size); FILE *out = fopen(indexes[i].name, "wb"); if (!out) { printf("无法创建文件: %s\n", indexes[i].name); continue; } // 读取并写入文件数据 long remaining = indexes[i].size; char buffer[4096]; // 这段代码是用于分块读取文件数据的逻辑。 /* remaining 变量 表示文件还剩下多少字节需要读取 初始值是文件总大小 每次读取后减少已读取的字节数*/ /* 这个循环就像用勺子舀水: remaining = 锅里还剩多少水 buffer = 勺子的大小(固定4KB) to_read = 这次要舀多少(如果水少就少舀点) 每次舀一勺,直到舀完为止*/ while (remaining > 0) { size_t to_read = sizeof(buffer); if (remaining < (long)to_read) { to_read = remaining; } size_t read = fread(buffer, 1, to_read, pack); if (read == 0) break; fwrite(buffer, 1, read, out); remaining -= read; } fclose(out); } free(indexes); fclose(pack); printf("解包完成!\n"); } // 主函数 int main(int argc, char *argv[]) { if (argc != 3) { printf("使用方法:\n"); printf(" 打包: %s -pack 文件夹名\n", argv[0]); printf(" 解包: %s -unpack archive.dat\n", argv[0]); return 1; } if (strcmp(argv[1], "-pack") == 0) { pack_folder(argv[2]); } else if (strcmp(argv[1], "-unpack") == 0) { unpack_files(argv[2]); } else { printf("参数错误\n"); return 1; } return 0; }
浙公网安备 33010602011771号