5

https://tukaani.org/xz/java.html This site provide a XZ Library for compress/decompress files, I would like to give it a shot but I am lost.

Anyone got experience on this? Or a tutorial? Thanks.

Saroj Raut
  • 123
  • 2
  • 9
  • You could find a similar tutorial here, which using gz, you just swap GzipCompressorInputStream with XZCompressorInputStream. And remember to add the dependency, that's all :) https://stackoverflow.com/a/55736666/1083128 – Mia Dec 26 '19 at 06:34

3 Answers3

4

I have used this library recently and this is the working code on my github link XZ compression algorithm. you can use this class in your android project. This is Main class to give the idea of how to use this 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
}

Note: XZ compression algorithm needs lots of memory to run. It's not recommended to use it for any mobile platform like Android. It will give you out of memory exception. Android provides ZLIB compression library called Deflater and Inflater. This works well on Android platform.

Jai Prak
  • 2,855
  • 4
  • 29
  • 37
0

You can use XZ-Java static library from Android AOSP or 'org.tukaani:xz:1.8'lib to compress the files in XZ file format. Here is working code to compress the file in XZ format.Create the Asynctask for compressing multiple files and use the below java code to compress.

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());
        }
}
0

My Android app loads a data file from its assets directory on startup, and I already know the decompressed size, so all I needed to write was:

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

and then git clone https://git.tukaani.org/xz-java.git and cp -r xz-java/src/org into my app's src directory (and ensure all .java files are mentioned on my javac command line—I still use old-school command-line scripts to compile my apps; I haven't set them up for Android Studio or Gradle).

However, the resulting app took six seconds to decompress 3M of compressed data on a 2013 Sony Xperia Z Ultra (Android 4.4), and changing the compression level of xz did not noticeably affect that 6-second startup. Yes it only took 1 second on a 2018 Samsung S9 running Android 10, but it's the older phones that need more compression, as they're the ones with less space available, so adding an unacceptable startup delay to the app on older devices seems to be self-defeating, especially if the alternative java.util.zip.Inflater is near instantaneous:

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 */

and for that fast startup you pay only a 20% increase in the APK size over the one with the xz file (I compressed using zopfli to get a tiny bit smaller than gzip -9 although it's still bigger than xz -0).

Tukaani's code doesn't currently seem to make an equivalent of setInput available. Tukaani's XZDecDemo.java contains the comment "Since XZInputStream does some buffering internally anyway, BufferedInputStream doesn't seem to be needed here to improve performance", but for completeness I tried it anyway:

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);

however this made no noticeable difference to the 6-second delay (so it seems the comment is correct: the performance is just as bad either way).

Silas S. Brown
  • 1,469
  • 1
  • 17
  • 18