王学岗性能优化(12)——7z压缩

                             **(上)**

1,
(1)7Z是什么:
一种文件压缩格式,具有高压缩比率,进行数据压缩有多种压缩算法可以选择。与其它压缩格式相比,得到的压缩文档较小,即压缩率最高
(2)7-Zip:
完全免费而且开源的压缩软件,相比其他软件有更高的压缩比但同时耗费的资源也相对更多。支持压缩/ 解压缩:7z, XZ, BZIP2, GZIP, TAR, ZIP,WIM
(3)7z的好处:
节省磁盘的空间,节省上传下载的流量
(4)常见的压缩格式:
zip:一种规范开放的压缩文件,压缩算法主要使用 (原名DEFLATE /真空)
rar:RAR有专利保护,特别是编码也就是压缩程序是私有的。
tar:tar是Linux常见的一种归档文件格式(原生不包括压缩功能,压缩率最 差),tar一般和其他没有文件管理的压缩算法文件结合使用,用tar打包整个文件 目录结构成一个文件,再用gzip,bzip等压缩 。是Linux常见的压缩归档的处理 方法。
(5)7z:算法主要用lzma,7z的文件和管理程序都是开源的。
(6)压缩比较
文件压缩得分 文件压缩时间x压缩率(得分越低越牛)在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
(7)7zip的使用(在windows环境下)
1)下载地址:http://www.7-zip.org/
2)下载安装后的7-zip在这里插入图片描述
3)源码下载地址https://sourceforge.net/projects/p7zip/files/
4)压缩等级
不压缩0(就是拷贝文件)
快速压缩1
正常压缩5(默认值)
最大压缩7
极限压缩9
5)压缩命令
7z a [输出文件] [待压缩文件/目录] -mx=9
9是压缩等级

cmd 进入当前目录
输入如下命令

7z a ../gang -mx=0

这个命令是把当前所有文件都压缩到…/gang的目录,压缩等级是0
6)解压命令

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

注意-O与输出目录之间没有空格
我们把第六小点压缩的文件在解压回来

7z x ../gang.7z -o../gang

(8)7zip的使用(在android环境下)
1)源码下载地址:

https://sourceforge.net/projects/p7zip/files/

2)命令行中使用

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

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

第一步:
我们看下目录
在这里插入图片描述
-进入 目录/CPP/ANDROID/7zr
android目录中有三个文件夹,7z,7za,7zr
7z:使用了插件,能进行更多的格式支持(能支持tar、zip等)
7za:只是用7zip
7zr:只支持7z格式
我们这里只用7zr,我们来到7zr目录。目录下有两个文件
jni文件夹和makefile文件
我们看下makefile文件


TARGET=7zr

include ../makefile.inc

test: install
	adb shell $(DEVICE_DIR)/7zr b

test_crc: install
	adb shell $(DEVICE_DIR)/7zr -mm=crc b

test_complex: install
	adb shell $(DEVICE_DIR)/7zr "-mm=*" b

test2:
	adb push ./libs/armeabi-v7a/7zr $(DEVICE_DIR)/7zr-v7a
	adb shell chmod 777 $(DEVICE_DIR)/7zr-v7a
	adb shell $(DEVICE_DIR)/7zr-v7a b

test_all: install
	adb push ../../../check/test/7zr433_7zip_lzma.7z $(DEVICE_DIR)
	adb shell $(DEVICE_DIR)/7zr t  $(DEVICE_DIR)/7zr433_7zip_lzma.7z

bench: install test

# FIXME这里是操作步骤
debug:
	cd jni ; ndk-build NDK_DEBUG=1
	adb push ./libs/armeabi/7zr /data/app/
	adb push ./libs/armeabi/gdbserver /data/app/
	adb shell chmod 777 /data/app/7zr
	adb shell chmod 777 /data/app/gdbserver
	adb forward tcp:1234: tcp:1234
	adb shell  /data/app/gdbserver :1234 /data/app/7zr
	

第二步:
默认编译出armeabi架构,可以根据自己的需要在CPP/ANDROID/7zr/jni/Application.mk中增加/修改,如编译armeabi-v7a和x86:
操作如下
APP_ABI := x86
改为:
APP_ABI := armeabi-v7a x86
这是Application.mk文件

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

CPP/ANDROID/7zr/jni目录下有两个文件,除了Application.mk外,还有一个Android.mk.我们看下它的部分代码

扫描二维码关注公众号,回复: 6512814 查看本文章
# Needed since ANDROID 5, these programs run on android-16 (Android 4.1+)
#与位置无关的可执行程序
LOCAL_CFLAGS += -fPIE
LOCAL_LDFLAGS += -fPIE -pie
#编译可执行文件
include $(BUILD_EXECUTABLE)
#编译动态库
#include $(BUILD_SHARED_LIBRARY)
#编译静态库
#include $(BUILD_STATIC_LIBRARY)

第三部 执行编译:jni在我的计算机上的目录是……\p7zip_16.02_src_all\p7zip_16.02\CPP\ANDROID\7zr\jni
cd jni
ndk-build
运行完之后会生成一个obj文件夹和一个libs文件件

cd obj
cd libs
你会发现有一个armeabi-v7a的文件夹和一个x86文件夹,就是我们刚才用ndk-build编译生成的。
得到一个可执行文件7zr
第三部拷贝到android 工程
我们新建一个NDK工程,把libs文件夹拷贝到android assets目录,如下图所示
在这里插入图片描述
看下我们的布局文件,很简单,就三个按钮

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.dn.lsn_12_demo.MainActivity">

    <Button
        android:onClick="load"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="加载可执行文件" />

    <Button
        android:onClick="pack"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="打包7z文件" />
    <Button
        android:onClick="unpack"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="解包7z文件" />

</LinearLayout>

点击加载可执行文件,然后执行打包7z文件,然后执行解包7z文件
工具类

package com.dn.lsn_12_demo.command;

import android.content.Context;
import android.os.Build;
import android.util.Log;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.List;

/**
 * @author Damon
 * @date 2019/05/27
 */
public class CommandUtils {

    /**
     * 拷贝文件
     *
     * @param context
     * @param binary
     * @return
     */
    public static boolean copyAssets2File(Context context, String binary) {
        // /data/data/package
        File filesDirectory = context.getFilesDir();
        boolean ret = false;
        InputStream is = null;
        FileOutputStream fos = null;
        try {
            //根据cpu 拷贝不同的可执行文件
            Log.e("Build.CPU_ABI: ",Build.CPU_ABI);
            List<String> abiNames = Arrays.asList(context.getAssets().list("libs"));
            if(!abiNames.contains(Build.CPU_ABI)){
                return false;
            }
            is = context.getAssets().open("libs/" + Build.CPU_ABI + "/" + binary);

            fos = new FileOutputStream(new File(filesDirectory,
                    binary));
            byte[] buffer = new byte[2048];
            int n;
            while ((n = is.read(buffer)) != -1) {
                fos.write(buffer, 0, n);
            }
            fos.flush();
            ret = true;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (null != is) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != fos) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return ret;
    }

    public static String inputStream2String(InputStream inputStream) {
        try {
            BufferedReader r = new BufferedReader(new InputStreamReader(inputStream));
            String str;
            StringBuilder sb = new StringBuilder();
            while ((str = r.readLine()) != null) {
                sb.append(str);
            }
            return sb.toString();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}

package com.dn.lsn_12_demo;

import android.content.Context;
import android.os.AsyncTask;


import com.dn.lsn_12_demo.command.CommandUtils;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * @author Damon
 * @date 2019/05/27
 */

public class ZipHelper {
    /**
     * 执行结果回调
     */
    public interface OnResultListener {
        void onSuccess(String msg);

        void onFailure(int errorno, String msg);

        void onProgress(String msg);
    }

    /**
     * 将可执行文件 从assets拷贝到 /data/data/包名 下
     *
     * @param context
     * @param binaryName
     * @return
     */
    public static boolean loadBinary(Context context, String binaryName) {
        //  把assets目录下的可执行文件拷贝到/data/data/包名
        File binaryFile = new File(context.getFilesDir(), binaryName);
        if (binaryFile.exists()) {
            //存在 但不能执行
            if (!binaryFile.canExecute()) {
                //设置可执行并 返回加过
                binaryFile.setExecutable(true);
            }
        } else {
            //根据cpu abi拷贝可执行文件
            if (CommandUtils.copyAssets2File(context, binaryName)) {
                if (!binaryFile.canExecute()) {
                    //设置可执行并 返回加过
                    binaryFile.setExecutable(true);
                }
            }
        }
        return binaryFile.exists() && binaryFile.canExecute();
    }

    public static void execute(Context context, String cmd, OnResultListener listener) {
        File filesDir = context.getFilesDir();
        // /data/data/包名/7zr
        new ExecuteAysnTask(filesDir.getAbsolutePath() + "/" + cmd, listener).execute();
    }

    /**
     * 结果记录
     */
    static class Result {
        boolean success;
        String output;
        int errorno;

        public Result(boolean success, String output, int errorno) {
            this.success = success;
            this.output = output;
            this.errorno = errorno;
        }
    }


    static class ExecuteAysnTask extends AsyncTask<Void, String, Result> {
        private OnResultListener listener;
        private String cmd;

        public ExecuteAysnTask(String cmd, OnResultListener listener) {
            this.cmd = cmd;
            this.listener = listener;
        }

        @Override
        protected Result doInBackground(Void... voids) {
            Process process = null;
            //执行结果输出
            String out;
            try {
                //执行任务
                process = Runtime.getRuntime().exec(cmd);
                //查看是否执行完成
                while (!isComplete(process)) {
                    //读取运行过程中的输出信息
                    BufferedReader reader = new BufferedReader(new InputStreamReader
                            (process.getInputStream()));
                    String line;
                    while ((line = reader.readLine()) != null) {
                        //报告执行过程
                        publishProgress(line);
                    }
                }
                int exitValue = process.exitValue();
                //成功
                if (exitValue == 0) {
                    out = CommandUtils.inputStream2String(process.getInputStream());
                } else {
                    out = CommandUtils.inputStream2String(process.getErrorStream());
                }
                return new Result(exitValue == 0, out, exitValue);
            } catch (IOException e) {
                e.printStackTrace();
                out = e.getMessage();
            } finally {
                if (null != process) {
                    process.destroy();
                }
            }
            return new Result(false, out, -1);
        }

        @Override
        protected void onProgressUpdate(String... values) {
            listener.onProgress(values[0]);
        }

        @Override
        protected void onPostExecute(Result result) {
            if (result.success) {
                listener.onSuccess(result.output);
            } else {
                listener.onFailure(result.errorno, result.output);
            }
        }

        /**
         * 查看程序是否结束
         *
         * @param process
         * @return
         */
        private boolean isComplete(Process process) {
            try {
                //如果已经结束则返回结果 否则会出现IllegalThreadStateException异常
                process.exitValue();
                return true;
            } catch (IllegalThreadStateException e) {
            }
            return false;
        }
    }
}

Actitivity中调用

package com.dn.lsn_12_demo;

import android.Manifest;
import android.content.pm.PackageManager;
import android.nfc.Tag;
import android.os.Build;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

import com.dn.lsn_12_demo.R;

import java.io.File;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //动态申请权限,因为等下我们解压压缩需要用到sd卡
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            String[] perms = {Manifest.permission.WRITE_EXTERNAL_STORAGE};
            if (checkSelfPermission(perms[0]) == PackageManager.PERMISSION_DENIED) {
                requestPermissions(perms, 200);
            }
        }
        File src = new File(Environment.getExternalStorageDirectory(), "7-Zip");
        File out = new File(Environment.getExternalStorageDirectory(), "7-Zip.7z");
        int result = ZipCode.exec("7zr a " + out.getAbsolutePath() + " "
                + src.getAbsolutePath() + " -mx=9");
        Log.e(TAG, "ZipCode.exec: "+result);
    }

    /**
     * 将assets下的可执行文件拷贝到应用私有目录
     *
     * @param view
     */
    public void load(View view) {
        boolean result = ZipHelper.loadBinary(this, "7zr");
        Toast.makeText(this, "加载7zr结果:" + result, Toast.LENGTH_SHORT).show();
    }

    /**
     * 压缩
     * 7zr a  [输出文件] [待压缩文件/目录] -mx=9
     * 7zr a /sdcard/7-Zip.7z /sdcard/7-Zip -mx=9
     *
     * @param view
     */
    public void pack(View view) {
        //待压缩的文件
        //9表示压缩等级
        File src = new File(Environment.getExternalStorageDirectory(), "7-Zip");
        File out = new File(Environment.getExternalStorageDirectory(), "7-Zip.7z");
        ZipHelper.execute(this, "7zr a " + out.getAbsolutePath() + " "
                + src.getAbsolutePath() + " -mx=9", new ZipHelper.OnResultListener() {
            @Override
            public void onSuccess(String msg) {
                Log.e(TAG, "执行成功");
            }

            @Override
            public void onFailure(int errorno, String msg) {
                Log.e(TAG, "执行失败");
                Log.e(TAG, "错误码:"+errorno);
                Log.e(TAG, "错误信息:"+msg);
            }

            @Override
            public void onProgress(String msg)
            {
                //输出编译过程中的日志
                Log.e(TAG, "正在执行:" + msg);
            }
        });
    }

    /**
     * 解压
     * 7zr x [压缩文件]  -o[输出目录]
     *
     * @param view
     */
    public void unpack(View view) {

        File src = new File(Environment.getExternalStorageDirectory(), "7-Zip.7z");
        File out = new File(Environment.getExternalStorageDirectory(), "7-Zip-unpack");
        ZipHelper.execute(this, "7zr x " + src.getAbsolutePath() + " -o"
                + out.getAbsolutePath(), new ZipHelper.OnResultListener() {
            @Override
            public void onSuccess(String msg) {
                Log.e(TAG, "执行成功");
            }

            @Override
            public void onFailure(int errorno, String msg) {
                Log.e(TAG, "执行失败");
                Log.e(TAG, "错误码:"+errorno);
                Log.e(TAG, "错误信息:"+msg);
            }

            @Override
            public void onProgress(String msg) {
                //输出编译过程中的日志
                Log.e(TAG, "正在执行:" + msg);
            }
        });
    }
}

在这里插入图片描述
看下运行结果
介绍一个小技巧,android studio中如何查看sdcard目录
在这里插入图片描述
(下)

猜你喜欢

转载自blog.csdn.net/qczg_wxg/article/details/90749643