5

I would like to compress an String manually defined to 7z in Java. So then I could convert it to base64. I found many examples compressing files to 7z and then saving into new File.

I just try the next code, and it takes correctly the file and compress it:

private static void addToArchiveCompression(SevenZOutputFile out, File file, String dir) throws IOException {
        String name = dir + File.separator + file.getName();
        if (file.isFile()){
            SevenZArchiveEntry entry = out.createArchiveEntry(file, name);
            out.putArchiveEntry(entry);

            FileInputStream in = new FileInputStream(file);
            byte[] b = new byte[1024];
            int count = 0;
            while ((count = in.read(b)) > 0) {
                out.write(b, 0, count);
            }
            out.closeArchiveEntry();

        } else if (file.isDirectory()) {
            File[] children = file.listFiles();
            if (children != null){
                for (File child : children){
                    addToArchiveCompression(out, child, name);
                }
            }
        } else {
            System.out.println(file.getName() + " is not supported");
        }
    }  

But how can I compress an manually defined String to 7z and convert it to byte[]? So then I can convert the byte[] to base64 and print it, without generating or reading new Files?

1
  • can you share the code for compressing defined String to 7z and convert it into bytes array. Commented Sep 5, 2019 at 11:50

4 Answers 4

4

Since you are already using commons-compress for 7zip compression you can create SevenZOutputFile(SeekableByteChannel) instance with SeekableInMemoryByteChannel that wraps a byte array. As per javadoc:

A SeekableByteChannel implementation that wraps a byte[].

When this channel is used for writing an internal buffer grows to accommodate incoming data. A natural size limit is the value of Integer.MAX_VALUE. Internal buffer can be accessed via array().

Something like:

SeekableInMemoryByteChannel channel = new SeekableInMemoryByteChannel(new byte[1024]);
SevenZOutputFile out = new SevenZOutputFile(channel);
// modified addToArchiveCompression(out, ...); for String
// encode channel.array() to Base64
Sign up to request clarification or add additional context in comments.

Comments

1

This is a bit offtopic, but assuming that LZMA is part of 7zip, this might help you:

public static byte[]compress(byte[]arr,int level){
    try {
        ByteArrayOutputStream compr = new ByteArrayOutputStream();
        LZMA2Options options = new LZMA2Options();
        options.setPreset(level); // play with this number: 6 is default but 7 works better for mid sized archives ( > 8mb)
        XZOutputStream out = new XZOutputStream(compr, options);
        out.write(arr);
        out.finish();
        return compr.toByteArray();
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

public static byte[]decompress(byte[]bts){
    try {
        ByteArrayInputStream bis = new ByteArrayInputStream(bts);
        XZInputStream is = new XZInputStream(bis);
        ByteArrayInputStream decomp = new ByteArrayInputStream(is.readAllBytes());
        ObjectInputStream ois = new ObjectInputStream(decomp);
        byte data[]= (byte[]) ois.readObject();
        return data;
    } catch (IOException | ClassNotFoundException e) {
        throw new RuntimeException(e);
    }
}

maven dependency:

    <dependency>
        <groupId>org.tukaani</groupId>
        <artifactId>xz</artifactId>
        <version>1.8</version>
    </dependency>

convert your String to byte[] with s.getBytes(StandardCharsets.UTF_8);

Comments

0

You will of course have to apply several changes to the code you posted. That code is meant to compress a file or directory whereas your case is much simpler. You definitely won't need a for loop, for example.

I break down the various parts you'll have to look into and leave the coding to you.

Converting a String to data for 7z:

One of the options is to use a ByteArrayInputStream instead of a FileInputStream. The ByteArrayInputStream will have to be initialised with the bytes corresponding to the String.

See the following article for an example on how to do this conversion:

https://www.baeldung.com/convert-string-to-input-stream

Converting output bytes to Base64:

There are several approaches, detailed in this StackOverflow thread:

How do I convert a byte array to Base64 in Java?

Outputting 7z to memory instead of File:

You will have to use the SevenZOutputFile constructor taking a SeekableByteChannel interface as input. Your implementation of SeekableByteChannel will have to be backed by a byte array or stream of sorts. You can use the following implementation:

https://commons.apache.org/proper/commons-compress/apidocs/org/apache/commons/compress/utils/SeekableInMemoryByteChannel.html

Obtaining a SevenZArchiveEntry from something other than a file:

Although the SevenZOutputFile class doesn't seem to provide a facility to do that, if you look at its sourcecode you'll notice that you can manually create a SevenZArchiveEntry without any intermediation, as it has an empty constructor. You'll have to "pretend" it's still an actual file, but that shouldn't be a problem.

Sourcecode of SevenZArchiveEntry:

https://commons.apache.org/proper/commons-compress/apidocs/src-html/org/apache/commons/compress/archivers/sevenz/SevenZOutputFile.html

Comments

0

I found that someone had implemented the code.

import java.io.ByteArrayOutputStream;
import java.io.IOException;

import org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry;
import org.apache.commons.compress.archivers.sevenz.SevenZFile;
import org.apache.commons.compress.archivers.sevenz.SevenZOutputFile;
import org.apache.commons.compress.utils.SeekableInMemoryByteChannel;

/**
 * the SevenZ Util
 *
 * @author ph3636
 */
public class SevenZUtil {

    private static final int BUFFER_SIZE = 8192;

    public static byte[] compress(byte[] bytes) {
        if (bytes == null) {
            throw new NullPointerException("bytes is null");
        }
        SeekableInMemoryByteChannel channel = new SeekableInMemoryByteChannel();
        try (SevenZOutputFile z7z = new SevenZOutputFile(channel)) {
            SevenZArchiveEntry entry = new SevenZArchiveEntry();
            entry.setName("sevenZip");
            entry.setSize(bytes.length);
            z7z.putArchiveEntry(entry);
            z7z.write(bytes);
            z7z.closeArchiveEntry();
            z7z.finish();
            return channel.array();
        } catch (IOException e) {
            throw new RuntimeException("SevenZ compress error", e);
        }
    }

    public static byte[] decompress(byte[] bytes) {
        if (bytes == null) {
            throw new NullPointerException("bytes is null");
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        SeekableInMemoryByteChannel channel = new SeekableInMemoryByteChannel(bytes);
        try (SevenZFile sevenZFile = new SevenZFile(channel)) {
            byte[] buffer = new byte[BUFFER_SIZE];
            while (sevenZFile.getNextEntry() != null) {
                int n;
                while ((n = sevenZFile.read(buffer)) > -1) {
                    out.write(buffer, 0, n);
                }
            }
            return out.toByteArray();
        } catch (IOException e) {
            throw new RuntimeException("SevenZ decompress error", e);
        }
    }
}
<commons-compress.version>1.22</commons-compress.version>
<xz.version>1.9</xz.version>
<dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-compress</artifactId>
            <version>${commons-compress.version}</version>
</dependency>
<dependency>
            <groupId>org.tukaani</groupId>
            <artifactId>xz</artifactId>
            <version>${xz.version}</version>
</dependency>

reference: SevenZUtil.java

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.