GZIP Java против .NET - PullRequest
       18

GZIP Java против .NET

3 голосов
/ 29 апреля 2010

Использование следующего кода Java для сжатия / распаковки байтов [] в / из GZIP. Первые байты текста в байтах gzip:

public static byte[] fromByteToGByte(byte[] bytes) {
    ByteArrayOutputStream baos = null;
    try {
        ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
        baos = new ByteArrayOutputStream();
        GZIPOutputStream gzos = new GZIPOutputStream(baos);
        byte[] buffer = new byte[1024];
        int len;
        while((len = bais.read(buffer)) >= 0) {
            gzos.write(buffer, 0, len);
        }
        gzos.close();
        baos.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return(baos.toByteArray());
}

Тогда метод, который идет другим путем, сжал байты в несжатые байты:

public static byte[] fromGByteToByte(byte[] gbytes) {
    ByteArrayOutputStream baos = null;
    ByteArrayInputStream bais = new ByteArrayInputStream(gbytes);
    try {
        baos = new ByteArrayOutputStream();
        GZIPInputStream gzis = new GZIPInputStream(bais);
        byte[] bytes = new byte[1024];
        int len;
        while((len = gzis.read(bytes)) > 0) {
            baos.write(bytes, 0, len);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    return(baos.toByteArray());
}

Думаете, есть какой-нибудь эффект, так как я не пишу в файл gzip?
Также я заметил, что в стандартной функции C # BitConverter читает первые четыре байта, а затем вызывается функция MemoryStream Write с начальной точкой 4 и длиной входного буфера - 4. Так это влияет на достоверность заголовка?

Jim

Ответы [ 2 ]

8 голосов
/ 29 апреля 2010

Я попробовал это, и я не могу воспроизвести вашу проблему 'Недопустимый заголовок GZip'. Вот что я сделал:

Java сторона

Я взял ваш метод сжатия Java вместе с этим фрагментом кода Java:

public static String ToHexString(byte[] bytes){
    StringBuilder hexString = new StringBuilder();
        for (int i = 0; i < bytes.length; i++)
            hexString.append((i == 0 ? "" : "-") + 
                Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
    return hexString.toString();
}

Итак, это минималистичное Java-приложение, которое берет байты тестовой строки, сжимает ее и преобразовывает в шестнадцатеричную строку сжатых данных ...:

public static void main(String[] args){
    System.out.println(ToHexString(fromByteToGByte("asdf".getBytes())));
}

... выводит следующее (я добавил аннотации) :

1f-8b-08-00-00-00-00-00-00-00-4b-2c-4e-49-03-00-bd-f3-29-51-04-00-00-00
^------- GZip Header -------^ ^----------- Compressed data -----------^

C # сторона

Я написал два метода для сжатия и распаковки байтового массива в другой байтовый массив (метод сжатия только для полноты и моих тестов) :

public static byte[] Compress(byte[] uncompressed)
{
    using (MemoryStream ms = new MemoryStream())
    using (GZipStream gzs = new GZipStream(ms, CompressionMode.Compress))
    {
        gzs.Write(uncompressed, 0, uncompressed.Length);
        gzs.Close();
        return ms.ToArray();
    }
}

public static byte[] Decompress(byte[] compressed)
{
    byte[] buffer = new byte[4096];
    using (MemoryStream ms = new MemoryStream(compressed))
    using (GZipStream gzs = new GZipStream(ms, CompressionMode.Decompress))
    using (MemoryStream uncompressed = new MemoryStream())
    {
        for (int r = -1; r != 0; r = gzs.Read(buffer, 0, buffer.Length))
            if (r > 0) uncompressed.Write(buffer, 0, r);
        return uncompressed.ToArray();
    }
}

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

public static byte[] ToByteArray(string hexString)
{
    hexString = hexString.Replace("-", "");
    int NumberChars = hexString.Length;
    byte[] bytes = new byte[NumberChars / 2];
    for (int i = 0; i < NumberChars; i += 2)
        bytes[i / 2] = Convert.ToByte(hexString.Substring(i, 2), 16);
    return bytes;
}

... Я сделал следующее:

// Just hardcoded the output of the java program, convert it back to byte[]
byte[] fromjava = ToByteArray("1f-8b-08-00-00-00-00-00-00-00-" + 
                  "4b-2c-4e-49-03-00-bd-f3-29-51-04-00-00-00");

// Decompress it with my function above
byte[] uncompr = Decompress(fromjava);

// Get the string out of the byte[] and print it
Console.WriteLine(System.Text.ASCIIEncoding.ASCII
                    .GetString(uncompr, 0, uncompr.Length));

Et вуаля, вывод:

asdf

Прекрасно работает для меня. Возможно, вам следует проверить метод декомпрессии в вашем приложении c #.

Вы сказали в своем предыдущем вопросе, что храните эти байтовые массивы в базе данных, верно? Может быть, вы хотите проверить, возвращаются ли байты из базы данных так, как вы их поместили.

0 голосов
/ 29 апреля 2010

Публикуем это как ответ, чтобы код выглядел прилично. Обратите внимание на пару вещей:
Во-первых, обратное путешествие в базу данных не оказало никакого влияния. Java с обеих сторон произвела именно то, что я вставил. Java в C # out отлично работала с Ionic API, как и C # in и Java out. Что подводит меня ко второму пункту. Во-вторых, мой первоначальный распаковка был порядка:

public static string Decompress(byte[] gzBuffer)
{
    using (MemoryStream ms = new MemoryStream())
    {
        int msgLength = BitConverter.ToInt32(gzBuffer, 0);
        ms.Write(gzBuffer, 4, gzBuffer.Length – 4);
        byte[] buffer = new byte[msgLength];
        ms.Position = 0;
        using (GZipStream zip = new GZipStream(ms, CompressionMode.Decompress))
        {
            zip.Read(buffer, 0, buffer.Length);
        }
        return Encoding.UTF8.GetString(buffer);
    } 
}  

Что зависит от внутреннего количества байтов, вы читаете весь файл независимо от внутреннего значения. Не знаю, что такое алгоритм Ionic. Ваш работает так же, как методы Java, которые я использовал. Это единственное отличие, которое я вижу. Большое спасибо за всю эту работу. Я буду помнить этот способ сделать это. Спасибо, Jim

...