(十九)7-Zip 压缩

版权声明:本文为博主原创文章,未经博主允许不得转载。
本文纯个人学习笔记,由于水平有限,难免有所出错,有发现的可以交流一下。

一、概述

1.7z

一种文件压缩格式,具有高压缩比率,进行数据压缩有多种压缩算法可以选择。与其它压缩格式相比,得到的压缩文档较小,即压缩率最高,节省磁盘空间。

2.7-Zip

对 7z 的压缩格式,我们可以使用 7-Zip,下载地址

完全免费而且开源的压缩软件,相比其他软件有更高的压缩比但同时耗费的资源也相对更多。支持压缩/ 解压缩:7z, XZ, BZIP2, GZIP, TAR, ZIP, WIM。

3.数据

压缩率:
在这里插入图片描述

压缩文件尺寸:
在这里插入图片描述
压缩得分:
在这里插入图片描述
压缩时间:
在这里插入图片描述
整体来说,7-Zip 的性能相对较好。

二、7zip 的使用

1.压缩等级

0	不压缩
1	快速压缩
5	正常压缩
7	最大压缩
9	极限压缩

2.压缩命令

7z a   [输出文件] [待压缩文件/目录] -mx=9 

在这里插入图片描述

-t7z 	压缩文件的格式为7z(压缩zip则为-tzip)
-mx=9	设置压缩等级为极限压缩

3.解压命令

7z x [压缩文件]  -o[输出目录]

在这里插入图片描述

三、命令行使用 7z

1.下载源码

要在安卓中进行使用,我们需要先下载 7zip 的源码。下载地址
在这里插入图片描述

也可以使用命令行进行下载:

wget  https://jaist.dl.sourceforge.net/project/p7zip/p7zip/16.02/p7zip_16.02_src_all.tar.bz2

下载下来的是一个压缩包,进行解压查看。

2.选取格式

Runtime.getRuntime().exec(“xxx”)

7z 的使用不需要对执行过程进行干预,也就是不需要在执行过程中操作数据,只在乎最后得到一个 7z 文件或者解压出 7z 文件。因此可以使用命令行来使用 7zip 压缩与解压。(同理对于视频文件的压缩、转换也可以使用ffmpeg 命令行,但是对于实时编码摄像头数据就必须编码完成)

首先,我们需要在安卓手机中拥有 7zip 的可执行文件,类似 window 中的 7zip.exe。

进入刚才下载压缩包下的目录, ./CPP/ANDROID/7zr
在这里插入图片描述

7z	 使用了插件,能进行更多的格式支持(能支持 tar、zip 等)
7za	 只是用7zip
7zr  只支持7z格式

我们只需要 7z 的格式,所以这边我们采用的是 7zr,这是最精简的。(如果要使用 7za 的话也是可以,编译步骤一样)

3.编译

我们进入 7zr 目录,查看目录结构。
在这里插入图片描述
里面有个 makefile 文件,这个是在 eclipse 创建安卓项目时候使用,我们打开 makefile 文件进行查看,里面就有编译步骤。
在这里插入图片描述
进到 jni 目录进行查看,是两个 .mk 文件。
在这里插入图片描述

查看 Application.mk 文件。里面就是指定对应的平台,默认只有 armeabi,我们可以在这里进行对对应平台的添加。

# The ARMv7 is significanly faster due to the use of the hardware FPU
APP_ABI := armeabi
# p7zip armeabi and armeabi-v7a run at the same speed (p7zip does not use FPU)
# APP_ABI := armeabi armeabi-v7a
#APP_PLATFORM := android-8

修改为:

# The ARMv7 is significanly faster due to the use of the hardware FPU
APP_ABI := armeabi-v7a x86
# p7zip armeabi and armeabi-v7a run at the same speed (p7zip does not use FPU)
# APP_ABI := armeabi armeabi-v7a
#APP_PLATFORM := android-8

在 jni 目录下按 makefile 文件中写的,运行 ndk-build 。
在这里插入图片描述
注: NDK 的版本要使用旧的版本,否者会报错。这边个人是使用 ndk 12 进行编译,下载地址。(ndk 15 太新,编译出错,ndk 10 编译过得去,在项目运行时候 cmake 报错)

编译成功后的目录:
在这里插入图片描述

4.使用

先把生成的可执行文件拷贝到 assets 目录下,打包进 apk。
在这里插入图片描述
运行 7zip 前,先把可执行文件拷贝到安卓系统中。

	/**
	 * 把 7z 拷贝到手机
	 * @param view
	 */
	public void load(View view) {

		File diskFilename = new File(getFilesDir(), "7zr");

		//不存在,则进行拷贝
		if (!diskFilename.exists()) {
			String assetFilename;
			//根据cpu 拷贝不同的可执行文件
			if (Build.CPU_ABI.startsWith("armeabi") ||
					Build.CPU_ABI.equals("x86")) {
				assetFilename = "libs/" + Build.CPU_ABI + "/7zr";
			} else {
				Toast.makeText(this, "加载错误,平台不符", Toast.LENGTH_SHORT).show();
				return;
			}
			AssetsFileUtil.copyFromAssets(this, assetFilename, diskFilename.getAbsolutePath());
		}

		//存在但不能执行
		if (!diskFilename.canExecute()) {
			//设置可执行并
			diskFilename.setExecutable(true);
		}

		Toast.makeText(this, "加载7zr 结果:"
				+ (diskFilename.exists() && diskFilename.canExecute()),
				Toast.LENGTH_SHORT).show();
	}

然后使用代码进行 7zip 压缩和解压命令的执行。具体 demo 见末尾。

**注:**这边是对 sdcard 目录下的 7-Zip 文件夹进行压缩,所以在运行前需保证改文件夹存在。

四、NDK 使用 7z

1.设置编译动态库

在上面的配置基础上,配置编译成动态库。

修改 Android.mk 文件末尾,去除配置 pie,使用默认的。设置编译内容为动态库。

Android.mk

# Needed since ANDROID 5, these programs run on android-16 (Android 4.1+)
# pie 是给可执行程序使用的 flag
# LOCAL_CFLAGS += -fPIE
# LOCAL_LDFLAGS += -fPIE -pie

include $(BUILD_SHARED_LIBRARY)
# BUILD_EXECUTABLE 可执行文件
# BUILD_SHARED_LIBRARY 动态库
# BUILD_STATIC_LIBRARY 静态库

2.编译

与编译成执行文件一样的操作步骤,进行编译,等待一会,即可在 libs 下面生产对应的动态库。

3.添加动态库

新建 cpp/libs 文件夹,然后把生成的动态库拷贝进来。
在这里插入图片描述
在 app 下的 build.gradle 中添加 so 包的引用路径。(如果把 so 放在默认 jniLibs 文件夹下则不需要进行添加,也是可以的。)

android {
    ...
    sourceSets {
        main {
            jniLibs.srcDirs = ['src/main/cpp/libs']
        }
    }
}

4.配置 NDK 运行的平台

在 app 的 build.gradle 中进行添加以下配置:

android {
    compileSdkVersion 28
    defaultConfig {
		......
        externalNativeBuild {
            cmake {
                cppFlags ""
                abiFilters 'armeabi-v7a','x86'
            }
        }
    }
}

5.配置 CMakeLists

在 app 的 build.gradle 中添加 CMakeLists 路径。

android {
	......
    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }
}

在 app 下创建 CMakeLists.txt 文件。
在这里插入图片描述
CMakeLists.txt:

cmake_minimum_required(VERSION 3.4.1)

set(LIB_DIR ${CMAKE_SOURCE_DIR}/src/main/cpp/libs/${ANDROID_ABI})
add_library(lib7zr SHARED IMPORTED)
set_target_properties(lib7zr PROPERTIES IMPORTED_LOCATION ${LIB_DIR}/lib7zr.so)

#根据Android.mk引入头文件
#设置头文件查找目录
include_directories(src/main/cpp/lib7zr/CPP/7zip/Archive
src/main/cpp/lib7zr/CPP/7zip/Archive/7z
src/main/cpp/lib7zr/CPP/7zip/Archive/BZip2
src/main/cpp/lib7zr/CPP/7zip/Archive/Common
src/main/cpp/lib7zr/CPP/7zip/Archive/GZip
src/main/cpp/lib7zr/CPP/7zip/Archive/Cab
src/main/cpp/lib7zr/CPP/7zip/Archive/Lzma
src/main/cpp/lib7zr/CPP/7zip/Archive/Tar
src/main/cpp/lib7zr/CPP/7zip/Archive/Zip
src/main/cpp/lib7zr/CPP/7zip/Archive/Split
src/main/cpp/lib7zr/CPP/7zip/Archive/Z
src/main/cpp/lib7zr/CPP/7zip/Compress
src/main/cpp/lib7zr/CPP/7zip/Crypto
src/main/cpp/lib7zr/CPP/7zip/UI/Console
src/main/cpp/lib7zr/CPP/7zip/UI/Common
src/main/cpp/lib7zr/CPP/Windows
src/main/cpp/lib7zr/CPP/Common
src/main/cpp/lib7zr/CPP/7zip/Common
src/main/cpp/lib7zr/C
src/main/cpp/lib7zr/CPP/myWindows
src/main/cpp/lib7zr/CPP
src/main/cpp/lib7zr/CPP/include_windows)

add_library(
             native-lib
             SHARED
             src/main/cpp/native-lib.cpp
             )

target_link_libraries(
                    native-lib
                    lib7zr
                    log )

这个 CMakeLists.txt 编写是模仿 7zip 进行编写的。查看 Android.mk,把引用到的头文件拷贝进来就是了。

在这里插入图片描述

上面的 CMakeLists.txt 使用到了一些 7zip 的文件,我们需要把这些文件拷贝到 app/src/main/cpp/lib7zr 下。

7zip 下文件:
在这里插入图片描述

拷贝后文件:
在这里插入图片描述

6.编写 C 代码

在 app/src/main/cpp 下创建 native-lib.cpp 文件,进行 C 代码的编写。

native-lib:

#include <jni.h>
#include <string>
#include <7zTypes.h>
//
#include <android/log.h>

#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, "7zr",__VA_ARGS__);

//c++与c兼容
// int a(int x) i_ai
// i_a
//表示这个函数在别的地方实现
extern int MY_CDECL main
        (
#ifndef _WIN32
        int numArgs, char *args[]
#endif
);

void strArgs(const char *cmd, int &args, char pString[66][1024]);

extern "C"
JNIEXPORT jint JNICALL
Java_com_xiaoyue_project7zip_ZipCode_exec(JNIEnv *env, jclass type, jstring cmd_) {
    const char *cmd = env->GetStringUTFChars(cmd_, 0);
    //7zr a /sdcard/7-Zip.7z /sdcard/7-Zip -mx=9
    int numArgs;
    char temp[66][1024] = {0};
    //分割字符串 将值填入变量
    strArgs(cmd, numArgs, temp);
    char *args[] = {0};
    for (int i = 0; i < numArgs; ++i) {
        args[i] = temp[i];
        LOGE("%s", args[i]);
    }
    env->ReleaseStringUTFChars(cmd_, cmd);
    return main(numArgs,args);
}

void strArgs(const char *cmd, int &numArgs, char argv[66][1024]) {
    //获得字符串长度
    int size = strlen(cmd);
    //argv的两个下标
    int a = 0, b = 0;
    //0 = false
    //记录是否进入空格
    //7zr a /sdcard/7-Zip.7z /sdcard/7-Zip -mx=9
    //7zr\0
    int inspace = 0;
    for (int i = 0; i < size; ++i) {
        char c = cmd[i];
        switch (c) {
            case ' ':
            case '\t':
                if (inspace) {
                    //字符串结束符号
                    argv[a][b++] = '\0';
                    a++;
                    //加入下一个有效字符前 复原
                    b = 0;
                    inspace = 0;
                }
                break;
            default:
                //如果是字符
                inspace = 1;
                argv[a][b++] = c;
                break;
        }
    }
    //7zr a /sdcard/7-Zip.7z /sdcard/7-Zip -mx=9
    //如果最末尾不是空格 就不会进入  case ' ': case '\t': 补上最后一个结束符
    //if(inspace){}
    if (cmd[size - 1] != ' ' && cmd[size - 1] != '\t') {
        argv[a][b] = '\0';
        a++;
    }
    numArgs = a;
}

同时编写一个 java 类 ZipCode 进行加载 native-lib。

ZipCode:

public class ZipCode {
    static {
        System.loadLibrary("native-lib");
    }

    //7zr a xxx.7z xx
    public native static int exec(String cmd);
}

7.测试

在 MainActivity 中进行代码的调用。

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		File src = new File(Environment.getExternalStorageDirectory(), "7-Zip");
		File out = new File(Environment.getExternalStorageDirectory(), "7-Zip.7z");
		File out2 = new File(Environment.getExternalStorageDirectory(), "7-Zip_code");
		ZipCode.exec("7zr a " + out.getAbsolutePath() + " " + src.getAbsolutePath() + " -mx=9");
		ZipCode.exec("7zr x " + out.getAbsolutePath() + " -o" + out2.getAbsolutePath());
	}

注: 这边是对sdcard 目录下的 7-Zip 文件夹进行压缩,所以在运行前需保证改文件夹存在。

8.运行结果

在 sdcard 目录下生成 7-Zip.7z 压缩包和 7-Zip_code 解压文件夹。

五、使用场景

可以使用 7-Zip 对上传服务的文件进行压缩,减小体积。也可以使用 7-Zip 对 dex 文件进行压缩,减小 apk 的体积。

六、附

代码链接

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
7-zip 是一种高效的压缩算法,它能够提供比传统的 ZIP 压缩算法更高的压缩比率和更快的压缩速度。同时,它还支持多种压缩格式,包括 7z、ZIP、RAR、GZIP、TAR 等。 如果你想在 C 语言中使用 7-zip压缩算法,你可以使用 7-zip 的 C SDK。该 SDK 提供了一组 C 语言 API,可以让你在你的程序中使用 7-zip压缩和解压缩功能。 以下是使用 7-zip C SDK 进行压缩的基本步骤: 1. 包含 7-zip C SDK 的头文件。 ``` #include <7z.h> ``` 2. 定义一个结构体来存储压缩参数。 ``` CLzmaEncProps props; LzmaEncProps_Init(&props); props.level = 5; ``` 3. 打开要压缩的文件。 ``` HANDLE inFile = CreateFileA("input.txt", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); ``` 4. 创建一个输出文件。 ``` HANDLE outFile = CreateFileA("output.7z", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); ``` 5. 初始化 7-zip 压缩库。 ``` ISzAlloc alloc = { SzAlloc, SzFree }; CLzmaEncHandle enc; LzmaEnc_Construct(&enc); LzmaEnc_Alloc(&enc, 1024 * 1024, &alloc, &alloc); LzmaEnc_SetProps(&enc, &props); LzmaEnc_WriteProperties(&enc, outFile); ``` 6. 压缩文件。 ``` const int bufferSize = 64 * 1024; Byte inBuffer[bufferSize]; Byte outBuffer[bufferSize]; SZ_RESULT res = SZ_OK; UInt32 inSize = 0; UInt64 outSize = 0; for (;;) { DWORD bytesRead = 0; if (!ReadFile(inFile, inBuffer, bufferSize, &bytesRead, NULL)) { res = SZ_ERROR_READ; break; } if (bytesRead == 0) { break; } inSize += bytesRead; SRes res = LzmaEnc_Encode(&enc, outBuffer, &outSize, inBuffer, bytesRead, LZMA_FINISH_ANY); if (res != SZ_OK) { break; } DWORD bytesWritten = 0; if (!WriteFile(outFile, outBuffer, outSize, &bytesWritten, NULL)) { res = SZ_ERROR_WRITE; break; } } ``` 7. 关闭文件和 7-zip 压缩库。 ``` CloseHandle(inFile); CloseHandle(outFile); LzmaEnc_Destroy(&enc); ``` 这就是使用 7-zip C SDK 进行压缩的基本步骤。你可以根据你的具体需求进行调整和修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值