Linux C语言 Zlib 实现解压zip文件
Linux C语言 Zlib 实现解压zip文件
因为在做嵌入式Linux,做OTA功能的时候需要解压zip升级包。所以需要用到zip文件的解压缩功能。
就想着能不能用zlib来完成这个功能。在网上一通找以后,发现教程千篇一律,要么是打着解压文件的标题解压buff内容,要么是c++完成的。好不容易有两篇C语言解压zip文件的,结果并不能用。
最后还是只能看英文文档,终于找到案例了。下面记录如何实现的,其实还是非常的简单,例程写得比较复杂,我只用到一个解压功能,我只修改了一点代码,没有太大改动。有需要的话,可以再进行精简。上流程:
1. 安装zlib库
下载zlib。下载zlib source code
,官网能直接下载,也可以去github上下载。
解压编译安装zlib。
$ tar -xzvf zlib-1.2.11.tar.gz
$ cd zlib-1.2.11
$ ./configure
$ make
$ sudo make install
$ pkg-config zlib --libs --cflags
>> -I/usr/local/include -L/usr/local/lib –lz
安装成功。
2. 使用minizip
上面的源码目录contrib\minizip
即为minizip,是zip
和unzip
功能最小化实现。
打开Makefile文件,我们可以看到,这个目录下最终编译出来两个工具,一个是miniunz
,一个是minizip
。一个是zip的解压缩工具,一个文件的zip压缩工具。
CC=cc
CFLAGS=-O -I../..
UNZ_OBJS = miniunz.o unzip.o ioapi.o ../../libz.a
ZIP_OBJS = minizip.o zip.o ioapi.o ../../libz.a
.c.o:
$(CC) -c $(CFLAGS) $*.c
all: miniunz minizip
miniunz: $(UNZ_OBJS)
$(CC) $(CFLAGS) -o $@ $(UNZ_OBJS)
minizip: $(ZIP_OBJS)
$(CC) $(CFLAGS) -o $@ $(ZIP_OBJS)
test: miniunz minizip
./minizip test readme.txt
./miniunz -l test.zip
mv readme.txt readme.old
./miniunz test.zip
clean:
/bin/rm -f *.o *~ minizip miniunz
接下来对这个目录进行编译。
$ ./configure
$ make clean
$ make
经过编译,目录下能得到上面的两个工具。我们根据Makefile中的test的使用方法对两个工具进行使用。
$ echo "hello world!" > test.txt
$ ./minizip test.zip test.txt
# 可以看到一个目录下生成了test.zip
$ ./miniunz -l test.zip
# 可以看到压缩包的各种信息。打包压缩比,里面包含的文件等。
$ rm -r test.txt
$ ./miniunz test.zip
$ ls
# 好了,解压后,目录下的test.txt又出现了。
这里我们试一下用zip工具压缩test.txt,看看miniunz是否能够解压成功。
$ sudo apt install zip
$ rm test.zip
$ zip -o test.zip test.txt
$ ./miniunz test.zip
OK! 实践证明,代码是有没有问题。
这里解释一下,加-l
参数是只读取信息,不提取文件。
不加参数就是提取文件。压缩包里有多少文件就提取多少文件。可以通过在提供一个参数名,即压缩包内文件的文件名,可以直接只提取到对应的文件,如 ./miniunz test.zip test.txt
。加-d path
可以指定提取文件的输出路径。
这些参数的用法可以打开miniunz.c
进行查看。
如此完善的解压功能,代码本身可以直接拿来用,不过稍微有点臃肿,可以自己进行删减。
3. 修改miniunz.c
从上面的Makefile可以看出,编译我们需要的功能仅仅只需要gcc -O -I../.. -o miniunz miniunz.c unzip.o ioapi.o ../../libz.a
。即只需要unzip.c
和ioapi.c
文件,以及我们的自己的解压代码,还有zlib库。
这里我们需要修改miniunz.c
,事实上,这个文件里面的api基本上能直接拿来用。因为我只需要解压缩文件,并且我要解压的压缩包内只有一个文件,所以,我修改了一些代码。
$ touch demoUnzip.c
把需要的内容从miniunz.c
复制到我们的文件中。这里我把main()改成了下面的代码,仅仅只保留解压缩一个文件的功能。
$ gcc -O -I../.. -o demoUnzip demoUnzip.c unzip.o ioapi.o ../../libz.a
运行验证,结果完美。☺☺☺
int ch_unzip_file(char *zipFileName, char *srcPath, char *obFileName, char *obPath)
{
if (zipFileName == NULL || obFileName == NULL)
{
return -1;
}
unzFile uf = NULL;
char filename_try[MAXFILENAME + 16] = "";
int opt_do_extract_withoutpath = 0;
int opt_overwrite = 0;
int ret_value = 0;
const char *password = NULL;
char zipFile[64] = {0};
strcat(zipFile, srcPath);
strcat(zipFile, zipFileName);
#ifdef USEWIN32IOAPI
zlib_filefunc64_def ffunc;
#endif
strncpy(filename_try, zipFile, MAXFILENAME - 1);
/* strncpy doesnt append the trailing NULL, of the string is too long. */
filename_try[MAXFILENAME] = '\0';
#ifdef USEWIN32IOAPI
fill_win32_filefunc64A(&ffunc);
uf = unzOpen2_64(zipFile, &ffunc);
#else
uf = unzOpen64(zipFile);
#endif
if (uf == NULL)
{
strcat(filename_try, ".zip");
#ifdef USEWIN32IOAPI
uf = unzOpen2_64(filename_try, &ffunc);
#else
uf = unzOpen64(filename_try);
#endif
}
if (uf == NULL)
{
printf("Cannot open %s or %s.zip\n", zipFile, zipFile);
return 1;
}
printf("%s opened\n", filename_try);
ret_value = do_extract_onefile(uf, obFileName, opt_do_extract_withoutpath, opt_overwrite, password);
unzClose(uf);
return ret_value;
}
int main(int argc, char *argv[])
{
ch_unzip_file(argv[1], "", argv[2], "");
return 0;
}