zlib解压缩zip

      将zconf.h,zlib.h,zlibwapi.dll,zlibwapi.lib这4个文件放到项目目录下,并将头文件导入到工程中。

      将zlib-1.2.8\contrib\minizip文件夹下除miniunz.c和minizip.c以外的.h与.c文件放到项目目录下,并将zip.h与unzip.h导入到工程中。

      这样,就可以使用zip.h和unzip.h中的函数操作zip压缩包了。

      其中:

      zip.h负责压缩操作。

      unzip.h负责解压缩操作。

      注意:由于解压缩带密码的zip文件的功能被默认屏蔽,所以若要开启此功能,需要将unzip.c文件中的

#ifndef NOUNCRYPT
#define NOUNCRYPT
#endif

    改为:

#ifndef NOUNCRYPT
//        #define NOUNCRYPT
#endif

    这是因为在unzip.c的unzOpenCurrentFile3函数中:

extern int ZEXPORT unzOpenCurrentFile3(unzFile file, int* method, int* level, int raw, const char* password)
{
	……
#    ifndef NOUNCRYPT
		char source[12];
#    else
		if (password != NULL)
			return UNZ_PARAMERROR;
#    endif
	……
}

    NOUNCRYPT宏被定义,则当password!=NULL时,会直接返回UNZ_PARAMERROR

    修改了unzip.c文件后,zlibwapi.libzlibwapi.dll文件需要重新生成

解压缩

对于一个zip文件,内部可能有个文件夹嵌套,每个文件夹下都可能存在文件。

故读取zip文件,首先要对zip文件的信息进行获取,查看其内部有多少个文件,注释占多大空间。

初始状态下,会自动定位在第一个文件或文件夹。每处理完一个文件或文件夹,调用函数跳转到下一个文件或文件夹,直到所有文件或文件夹处理完毕。因此这需要一个for或者while循环。

对于每个文件或文件夹,都可以用函数来获取其文件名。因为可能会嵌套,故其文件名是包含相对路径的。若文件名以”/”结尾,则表明这是个文件夹。

实际上,所谓解压,就是将压缩包的数据读出来,然后写到另一个文件中。但另一个文件zlib库并不会为我们生成,故需要自己创建。也就是说,读出的第一个文件是文件夹,那么就要创建一个同名文件夹;读出的第二个文件是位于该文件夹下的一个png文件,那么就要在该文件夹下创建一个与png同名的文件,然后将解压出的数据写入。

其用到的函数如下:

1.    打开需要解压缩的文件:

unzFile unzOpen(const char *path);

传入zip文件的绝对路径,执行该函数会返回一个unzFile对象。这是一个void*指针,用于指向打开的zip文件。

后续的各种操作都要使用该unzFile对象。

对应地,操作完毕后需要关闭已打开的压缩文件:

int unzClose OF(unzFile file);

2.    获取zip文件的信息

int unzGetGlobalInfo(unzFile file, unz_global_info *pglobal_info);

传入通过1获取到的unzFile对象,传入一个空的unz_global_info*,函数执行完成后,会将zip文件的信息填充到该unz_global_info*指针中。

①   传入的unz_global_info定义如下:

typedef struct unz_global_info_s
{
	uLong number_entry;         // zip文件中的文件和文件夹总数
	uLong size_comment;         // zip文件的注释所占大小
} unz_global_info;

注意number_entry的值是zip文件中的文件盒文件夹总数。与是否嵌套无关。

例如:

将3个文件打包成一个zip,那么获取到的该值就是3;

一个文件夹A,含有2个文件以及一个子文件夹B;B中含有1个文件。直接对A进行打包,那么调用该函数获取到的值是5。这是因为这个压缩包中,共含有2个文件夹和3个文件,总数为5。

②   返回值为执行的结果信息。有以下取值:

#define UNZ_OK                          (0)
#define UNZ_END_OF_LIST_OF_FILE         (-100)
#define UNZ_ERRNO                       (Z_ERRNO)
#define UNZ_EOF                         (0)
#define UNZ_PARAMERROR                  (-102)
#define UNZ_BADZIPFILE                  (-103)
#define UNZ_INTERNALERROR               (-104)
#define UNZ_CRCERROR                    (-105)

3.    对于zip文件中定位的当前文件,可以通过函数来获取其信息:

int unzGetCurrentFileInfo(	unzFile file,
							unz_file_info *pfile_info,
							char *szFileName,
							uLong fileNameBufferSize,
							void *extraField,
							uLong extraFieldBufferSize,
							char *szComment,
							uLong commentBufferSize);

关于其参数:

①   unzFile file:已打开的unzFile对象

②   unz_file_info *pfile_info:一个头文件信息对象的指针,传入后,函数会将当前文件的信息填充到该指针指向的对象中。详见下面说明

③   char *szFileName:用于保存文件名,需在外部new出足够大的存储空间,函数会将文件的路径+文件名保存在该对象中。注意该文件名的路径是个相对路径,其最顶层为被压缩的最上层文件或文件夹

④   uLong fileNameBufferSize:与③统一,告知函数new了多大的char*内存

⑤   void* extraField:用于保存扩展内容,需在外部new出足够大的存储空间,函数会将文件的扩展内容保存在该对象中

⑥   uLong extraFieldBufferSize:与⑤统一,告知函数new了多大的内存

⑦   char* szComment:用于保存注释内容,需在外部new出足够大的存储空间,函数会将文件的注释内容保存在该对象中

⑧   uLong commentBufferSize:与⑦统一,告知函数new了多大的内存

对于其中的unz_file_info结构体,定义如下:

typedef struct unz_file_info_s
{
	uLong version;              // 压缩文件所使用的pkware版本	2 bytes
	uLong version_needed;       // 解压文件所需pkware版本		2 bytes
	uLong flag;                 // 全局方式位标记				2 bytes
	uLong compression_method;   // 压缩方式					2 bytes
	uLong dosDate;              // 文件最后修改日期时间			4 bytes
	uLong crc;                  // CRC-32校验					4 bytes
	uLong compressed_size;      // 压缩后大小					4 bytes
	uLong uncompressed_size;    // 未压缩大小					4 bytes
	uLong size_filename;        // 文件名长度					2 bytes
	uLong size_file_extra;      // 文件扩展字段长度				2 bytes
	uLong size_file_comment;    // 文件注释长度					2 bytes

	uLong disk_num_start;       // 磁盘开始号					2 bytes
	uLong internal_fa;          // 内部文件属性					2 bytes
	uLong external_fa;          // 外部文件属性					4 bytes

	tm_unz tmu_date;			   // 文件创建日期
} unz_file_info;

实际上,一般的zip文件很少使用扩展与注释。对于没有扩展与注释的,参数⑤⑦可以传入null,参数⑥⑧可以传入0。

注意获取到的文件名。若该文件名以路径分隔符”/”结尾,表明这是个文件夹;否则表明这是个文件。

判断一个文件名是文件还是文件夹,还可以利用external_fa字段。该字段的值会被填充为winnt.h中的FILE宏定义。通常,若external_fa  = 16,即0x00000010则说明是个文件夹;若external_fa   = 32,即0x00000020则说明是个文件。

在winnt.h中:

#define FILE_ATTRIBUTE_DIRECTORY            0x00000010  
#define FILE_ATTRIBUTE_ARCHIVE              0x00000020  

一般来说,在这里若external_fa !=FILE_ATTRIBUTE_DIRECTORY,则认为是个文件。

4.    对于已经定位到的zip中的单个文件,就可以执行解压缩了。解压缩过程如下:

①   打开该定位到的文件:

int unzOpenCurrentFile(unzFile file);

返回值为执行的结果信息。

对于加密的文件,需要传入密码:

int unzOpenCurrentFilePassword(unzFile file, const char* password);

若返回值不为UNZ_OK,则解压出错,可以根据返回值判断是文件本身问题还是解压问题。

②   读取文件内容:

int unzReadCurrentFile(unzFile file, voidp buf, unsigned len);

传入unzFile对象,创建一个缓冲区用于存放读取的内容,将缓冲区指针和大小传入。

由于缓冲区并不一定足够大,所以需要进行多次读取。每次读取,当前的读取位置都会被修改。

例如,一个文件读取需要10M空间。创建了一个1M大小的缓冲区。第一次调用该函数读取,当前位置指向文件的开始,读了1M大小的数据,将该数据存入缓冲区中;第二继续调用该函数来读取,此时当前位置由于第一次的读取,已经指向了1M数据结尾的地方,所以第二次读取会从1M结尾开始,读取1M大小的数据……调用该函数10次,即可读取完所有的数据。

文件的读取状况,是依靠返回值来判定的:

return>0:正常读取了文件的一部分内容,返回值为读取的字节数

return==0:没有数据被读取,说明文件已经读取完毕

return<0:读取出错,返回错误码

③   将缓冲区内容写入到创建的文件中:

这需要借助操作系统的函数来进行。同样是要对一个文件进行多次写入。

示例代码:

const int BUFFER_SIZE = 4096;
char szReadBuffer[BUFFER_SIZE];
while (TRUE)
{
	memset(szReadBuffer, 0, BUFFER_SIZE);	//清理缓冲区
	int nReadFileSize = unzReadCurrentFile(unzfile, szReadBuffer, BUFFER_SIZE);	//读取

	int result;
	if (nReadFileSize > 0)	result = 1;	//读取文件部分数据
	if (nReadFileSize == 0)	result = 0;	//读取文件结束
	if (nReadFileSize < 0)	result = -1;	//读取文件失败
	switch (result)
	{
	case 1:
	{
		//读取文件部分数据
		//将其写入到创建的文件中
	}
	break;
	case 0:
	{
		//读取文件结束
		unzCloseCurrentFile(unzfile);
		return;
	}
	break;
	case -1:
	{
		//读取文件失败
		unzCloseCurrentFile(unzfile);
	}
	break;
	}
}

5.    当前文件解析完毕,则跳转到下一个文件:

int unzGoToNextFile(unzFile file);

然后重复步骤3,4。

若成功,则return UNZ_OK

若失败,说明已到文件尾,则return UNZ_END_OF_LIST_OF_FILE

6.    对zip文件解压缩完毕后,要将文件关闭:

int unzClose(unzFile file);

7.    对于zip中各个文件和文件夹的定位,可以使用以下函数:

int unzGoToFirstFile(unzFile file);
int unzGoToNextFile(unzFile file);
int unzLocateFile(unzFile file, const char *szFileName, int iCaseSensitivity);

关于iCaseSensitivity参数:

iCaseSensitivity = 1则文件名的匹配区分大小写。

iCaseSensitivity = 2则文件名的匹配不区分大小写。

iCaseSensitivity = 0则文件名的匹配按操作系统自行决定。Unix使用1,Windows使用2

8.    对于zip中各个文件和文件夹的位置,可以使用索引:

typedef struct unz_file_pos_s
{
	uLong pos_in_zip_directory;   // 文件在zip文件中的偏移
	uLong num_of_file;            // 在文件中的索引
} unz_file_pos;

int unzGetFilePos(unzFile file, unz_file_pos* file_pos);
int unzGoToFilePos(unzFile file, unz_file_pos* file_pos);

unzGetFilePos函数会将当前定位文件的信息填入传入的unz_file_pos指针中。

unzGoToFilePos函数会根据传入的unz_file_pos指针中的信息,将当前文件定位到指定文件。

9.    获取zip文件的注释:

int unzGetGlobalComment(unzFile file, char *szComment, uLong uSizeBuf);

传入定义的缓存区首地址及其大小。

FreeRTOS是一个开源的实时操作系统,它提供了一套用于嵌入式系统的任务调度、内存管理、中断处理等功能。FreeRTOS本身并没有提供zip解压缩的功能,但可以通过集成第三方库来实现zip解压缩。 要在FreeRTOS中实现zip解压缩,可以使用一些开源的zip库,例如minizip或者zlib。这些库提供了zip文件的读取和解压缩功能。 首先,你需要将zip库的源代码添加到你的FreeRTOS项目中,并进行编译。然后,在你的应用程序中,你可以使用zip库提供的API来打开和解压缩zip文件。 以下是一个简单的示例代码,演示了如何在FreeRTOS中使用minizip库进行zip解压缩: ```c #include "unzip.h" void unzip_task(void *pvParameters) { const char *zipFilePath = "/path/to/your/zip/file.zip"; const char *extractPath = "/path/to/extract/files/"; unzFile zipFile = unzOpen(zipFilePath); if (zipFile == NULL) { // 处理打开zip文件失败的情况 vTaskDelete(NULL); } unz_global_info globalInfo; if (unzGetGlobalInfo(zipFile, &globalInfo) != UNZ_OK) { // 处理获取zip文件信息失败的情况 unzClose(zipFile); vTaskDelete(NULL); } char extractFilePath[256]; unz_file_info fileInfo; uLong i; for (i = 0; i < globalInfo.number_entry; i++) { if (unzGetCurrentFileInfo(zipFile, &fileInfo, extractFilePath, sizeof(extractFilePath), NULL, 0, NULL, 0) != UNZ_OK) { // 处理获取当前文件信息失败的情况 break; } if (unzOpenCurrentFile(zipFile) != UNZ_OK) { // 处理打开当前文件失败的情况 break; } // 创建文件并写入解压缩的数据 FILE *extractFile = fopen(extractFilePath, "wb"); if (extractFile == NULL) { // 处理创建文件失败的情况 unzCloseCurrentFile(zipFile); break; } char buffer[1024]; int readSize; while ((readSize = unzReadCurrentFile(zipFile, buffer, sizeof(buffer))) > 0) { fwrite(buffer, 1, readSize, extractFile); } fclose(extractFile); unzCloseCurrentFile(zipFile); if (unzGoToNextFile(zipFile) != UNZ_OK) { // 处理跳转到下一个文件失败的情况 break; } } unzClose(zipFile); vTaskDelete(NULL); } int main(void) { // 创建解压缩任务 xTaskCreate(unzip_task, "unzip_task", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL); // 启动FreeRTOS调度器 vTaskStartScheduler(); return 0; } ``` 在上面的示例代码中,我们创建了一个名为`unzip_task`的FreeRTOS任务,该任务负责打开和解压缩zip文件。你需要将`zipFilePath`和`extractPath`替换为你实际的zip文件路径和解压缩路径。 请注意,以上示例代码仅提供了基本的zip解压缩功能,你可能需要根据实际需求进行修改和扩展。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值