Распаковка byte[] с помощью LZ4

Я использую LZ4 для сжатия и распаковки строки. Я пробовал следующим образом

public class CompressionDemo {

    public static byte[] compressLZ4(LZ4Factory factory, String data) throws IOException {
        final int decompressedLength = data.getBytes().length;
        LZ4Compressor compressor = factory.fastCompressor();
        int maxCompressedLength = compressor.maxCompressedLength(decompressedLength);
        byte[] compressed = new byte[maxCompressedLength];
        compressor.compress(data.getBytes(), 0, decompressedLength, compressed, 0, maxCompressedLength);
        return compressed;

    }

    public static String deCompressLZ4(LZ4Factory factory, byte[] data) throws IOException {
        LZ4FastDecompressor decompressor = factory.fastDecompressor();
        byte[] restored = new byte[data.length];
        decompressor.decompress(data,0,restored, 0,data.length);
        return new String(restored);
    }

    public static void main(String[] args) throws IOException, DataFormatException {
        String string = "kjshfhshfashfhsakjfhksjafhkjsafhkjashfkjhfjkfhhjdshfhhjdfhdsjkfhdshfdskjfhksjdfhskjdhfkjsdhfk";
        LZ4Factory factory = LZ4Factory.fastestInstance();
        byte[] arr = compressLZ4(factory, string);
        System.out.println(arr.length);
        System.out.println(deCompressLZ4(factory, arr) + "decom");
    }
}

это дает следующее исключение

Исключение в потоке "main" net.jpountz.lz4.LZ4Exception: ошибка декодирования смещения 92 входного буфера

Проблема здесь в том, что распаковка работает только в том случае, если я передаю фактическую длину String byte[], т.е.

public static String deCompressLZ4(LZ4Factory factory, byte[] data) throws IOException {
        LZ4FastDecompressor decompressor = factory.fastDecompressor();
        byte[] restored = new byte[data.length];
        decompressor.decompress(data,0,restored, 0,"kjshfhshfashfhsakjfhksjafhkjsafhkjashfkjhfjkfhhjdshfhhjdfhdsjkfhdshfdskjfhksjdfhskjdhfkjsdhfk".getBytes().length);
        return new String(restored);
    }

Ожидается фактический размер строки byte[]. Может кто-то помочь мне с этим


person pppavan    schedule 13.05.2016    source источник
comment
@pppavan- Вы когда-нибудь находили решение своей проблемы?   -  person ketan    schedule 29.07.2017
comment
да, я решил это @kit   -  person pppavan    schedule 30.07.2017
comment
Большой. @pppavan Можете ли вы дать мне предложение по моей проблеме - stackoverflow.com/questions/45398848/ или, пожалуйста, дайте мне пример примера для распаковки массива.   -  person ketan    schedule 30.07.2017


Ответы (4)


Поскольку сжатие и распаковка могут происходить на разных машинах, или кодировка символов по умолчанию для машины не является одним из форматов Unicode, следует также указать кодировку.

В остальном он использует фактическую длину сжатия и распаковки, а также лучше сохраняет размер несжатых данных в простом формате, чтобы их можно было извлечь до распаковки.

public static byte[] compressLZ4(LZ4Factory factory, String data) throws IOException {
    byte[] decompressed = data.getBytes(StandardCharsets.UTF_8).length;
    LZ4Compressor compressor = factory.fastCompressor();
    int maxCompressedLength = compressor.maxCompressedLength(decompressed.length);
    byte[] compressed = new byte[4 + maxCompressedLength];
    int compressedSize = compressor.compress(decompressed, 0, decompressed.length,
                                             compressed, 4, maxCompressedLength);
    ByteBuffer.wrap(compressed).putInt(decompressed.length);
    return Arrays.copyOf(compressed, 0, 4 + compressedSize);
}

public static String deCompressLZ4(LZ4Factory factory, byte[] data) throws IOException {
    LZ4FastDecompressor decompressor = factory.fastDecompressor();
    int decrompressedLength = ByteBuffer.wrap(data).getInt();
    byte[] restored = new byte[decrompressedLength];
    decompressor.decompress(data, 4, restored, 0, decrompressedLength);
    return new String(restored, StandardCharsets.UTF_8);
}

Следует сказать, что String не подходит для двоичных данных, а ваше сжатие/распаковка предназначено только для обработки текста. (Строка содержит текст Unicode в виде двухбайтовых символов UTF-16. Преобразование в двоичные данные всегда включает преобразование с кодированием двоичных данных. Это требует памяти, скорости и возможного повреждения данных.)

person Joop Eggen    schedule 30.01.2018

Я только что столкнулся с той же ошибкой на Android и решил ее на основе следующей проблемы: https://github.com/lz4/lz4-java/issues/68

Короче говоря, убедитесь, что вы используете одну и ту же фабрику для обеих операций (сжатие + распаковка) и используйте Arrays.copyOf(), как показано ниже:

  byte[] compress(final byte[] data) {
     LZ4Factory lz4Factory = LZ4Factory.safeInstance();
     LZ4Compressor fastCompressor = lz4Factory.fastCompressor();
     int maxCompressedLength = fastCompressor.maxCompressedLength(data.length);
     byte[] comp = new byte[maxCompressedLength];
     int compressedLength = fastCompressor.compress(data, 0, data.length, comp, 0, maxCompressedLength);
     return Arrays.copyOf(comp, compressedLength);
}

  byte[] decompress(final byte[] compressed) {
     LZ4Factory lz4Factory = LZ4Factory.safeInstance();
     LZ4SafeDecompressor decompressor = lz4Factory.safeDecompressor();
     byte[] decomp = new byte[compressed.length * 4];//you might need to allocate more
     decomp = decompressor.decompress(Arrays.copyOf(compressed, compressed.length), decomp.length);
     return decomp;

Надеюсь, это поможет.

person M___K    schedule 30.01.2018

длина восстановленного byte[] слишком мала, вы не должны использовать сжатый data.length, вместо этого вы должны использовать data[].length * 3 или более 3.

person 苏国庆    schedule 03.06.2016
comment
Хотя это ответ, не могли бы вы предоставить больше информации, чтобы помочь другим? stackoverflow.com/help/how-to-answer - person Rich Benner; 03.06.2016

Я решил так:

public static byte[] decompress( byte[] finalCompressedArray,String ... extInfo) {
    int len = finalCompressedArray.length * 3;
    int i = 5;
    while (i > 0) {
        try {
            return decompress(finalCompressedArray, len);
        } catch (Exception e) {
            len = len * 2;
            i--;
            if (LOGGER.isInfoEnabled()) {
                LOGGER.info("decompress Error: extInfo ={} ", extInfo, e);
            }

        }

    }

    throw new ItemException(1, "decompress error");
}

/**
 * 解压一个数组
 *
 * @param finalCompressedArray 压缩后的数据
 * @param length               原始数据长度, 精确的长度,不能大,也不能小。
 * @return
 */
private static byte[] decompress(byte[] finalCompressedArray, int length) {
    byte[] desc = new byte[length ];
    int decompressLen = decompressor.decompress(finalCompressedArray, desc);

    byte[] result = new byte[decompressLen];
    System.arraycopy(desc,0,result,0,decompressLen);
    return result;
}
person 苏国庆    schedule 08.06.2016