如何将 XZ 库用于 compress/decompress 文件 android

how to use XZ lib to compress/decompress file in android

https://tukaani.org/xz/java.html 此站点为 compress/decompress 文件提供了一个 XZ 库,我想试一试,但我迷路了。

有人对此有经验吗?还是教程?谢谢

我最近使用了这个库,这是我 github link XZ compression algorithm 上的工作代码。您可以在 android 项目中使用此 class。这是 Main class 给出了如何使用此 class 的想法。

public static void main(String[] args){
  String input = "Some string blah blah blah";
  System.out.println("XZ or LZMA2 library.....");

  // If you are using some file instead of plain text you have to 
  //convert it to bytes here and pass it to `compress` method.

  byte[] xzCompressed = XZ_LZMA2.compress(input);
  System.out.println("Input length:" + input.length());
  System.out.println("XZ Compressed Length: "+ xzCompressed.length);
  String xzDecompressed = XZ_LZMA2.decompress(xzCompressed);
  System.out.println("XZ Decompressed : "+ xzDecompressed);

  // If you are using decompression for some compressed file instead of
  // plain text return bytes from `decompress` method and put it in 
  //FileOutputStream to get file back
}

注: XZ压缩算法需要大量内存才能运行。 不建议将其用于任何移动平台,例如Android。它会给你内存不足异常。 Android 提供 ZLIB 压缩库,名为 Deflater and Inflater。这在 Android 平台上运行良好。

您可以使用来自 Android AOSP 的 XZ-Java 静态库或 'org.tukaani:xz:1.8'lib 将文件压缩为 XZ 文件格式。这是压缩文件的工作代码 XZ format.Create 用于压缩多个文件的 Asynctask 并使用下面的 java 代码进行压缩。

Android.mk Changes for building in AOSP:
LOCAL_STATIC_JAVA_LIBRARIES := \
       xz-java
OR 

Gradle File Changes for building in Android Studio:
implementation 'org.tukaani:xz:1.8'

Java Code: 
public void CompressFile(String inputFile, String outputFile){
    XZOutputStream xzOStream = null;
        try {
            LZMA2Options opts = new LZMA2Options();
            opts.setPreset(7);

            FileOutputStream foStream = new FileOutputStream(outputFile);
            xzOStream = new XZOutputStream(foStream, opts);
            FileInputStream fiStream = new FileInputStream(inputFile);
            Scanner sc = null;

            try {
                sc = new Scanner(fiStream);
                while (sc.hasNextLine()) {
                    String line = sc.nextLine() + "\n";
                    xzOStream.write(line.getBytes(), 0, line.getBytes().length);
                }
                Utils.removeFile(inputFile);
            } finally {
                if (fiStream != null) {
                    fiStream.close();
                }

                if (sc != null) {
                    sc.close();
                }

                if(xzOStream != null)
                    xzOStream.close();

                if(foStream != null)
                    foStream.close();
            }
        }catch (Exception e){
            Log.e(TAG, "CompressFileXZ() Exception: " + e.toString());
        }
}

我的 Android 应用程序在启动时从它的 assets 目录加载一个数据文件,我已经知道解压后的大小,所以我只需要写:

byte[] data = new byte[ /* decompressed size here */ ];
new org.tukaani.xz.XZInputStream(context.getAssets().open("file.xz")).read(data);

然后 git clone https://git.tukaani.org/xz-java.gitcp -r xz-java/src/org 进入我的应用程序的 src 目录(并确保在我的 javac 命令行中提到所有 .java 文件——我仍然使用老式的命令行脚本来编译我的应用程序;我没有为 Android Studio 或 Gradle).

设置它们

但是, 生成的应用程序花了 6 秒 在 2013 索尼 Xperia Z Ultra 上解压 3M 的压缩数据(Android 4.4),更改 xz 的压缩级别并没有显着影响 6 秒启动。是的,在 2018 款三星 S9 运行 Android 10 上只用了 1 秒,但老款手机需要更多压缩,因为 它们是 较少 space 可用,因此在旧设备上向应用程序添加不可接受的启动延迟似乎是弄巧成拙,特别是如果替代方案 java.util.zip.Inflater 接近瞬时:

byte[] data = new byte[ /* compressed size here */];
context.getAssets().open("file.z").read(data);
java.util.zip.Inflater i=new java.util.zip.Inflater();
i.setInput(data);
byte[] decompressed=new byte[ /* decompressed size here */ ];
i.inflate(decompressed); i.end();
data = decompressed; /* allow earlier byte[] to be gc'd */

为了快速启动,与 xz 文件相比,APK 大小只增加 20%(我使用 zopfli 压缩比 gzip -9 虽然它仍然大于 xz -0).

Tukaani 的代码目前似乎没有提供等同于 setInput 的代码。 Tukaani 的 XZDecDemo.java 包含评论“由于 XZInputStream 无论如何都会在内部进行一些缓冲,因此此处似乎不需要 BufferedInputStream 来提高性能”,但为了完整起见,我还是尝试了它:

byte[] data = new byte[ /* decompressed size here */ ];
new org.tukaani.xz.XZInputStream(
    new java.io.BufferedInputStream(
        context.getAssets().open("file.xz"),
        /* compressed size here */)).read(data);

然而,这对 6 秒的延迟没有明显影响(因此评论似乎是正确的:无论哪种方式,性能都一样糟糕)。