Как мне записать сжатый байтовый массив через SFTP (Jsch) без распаковки? - PullRequest
4 голосов
/ 04 июня 2011

(Это было опубликовано в списке рассылки Jsch).Я читаю данные из базы данных и передаю их в виде байта [] (для передачи между компонентами промежуточного программного обеспечения).

Из этого байта [] я знаю, как создать файл gzipped в локальной файловой системе с помощьюкласс GZIPOutputStream.Я хочу создать файл gzipped в удаленной файловой системе, используя методы SFTP JSch.

Я сжал байт [] данных и передаю его как InputStream в библиотеку JSch дляSFTPing к удаленному файловому каталогу (как файл .gz).Однако доставленный файл имеет неожиданный EOF и не может быть «заархивирован»

gunzip: GlobalIssuer.xml.gz: неожиданный конец файла

Напоминание Я не передаю байт [], который является содержимым файла .gz, это содержимое записи базы данных

(Относительно) SSCCE выглядит следующим образом:

byte[] content = "Content".getBytes();
// It does work (I promise!) returns a 'gzipped' byte[]
byte[] gzippedContent = gzipContent(content);
ByteArrayInputStream bais = new ByteArrayInputStream(gzippedContent);
channelSftp.put(bais, "Content.txt.gz");

Метод gzipContent:

private byte[] gzipContent(byte[] content)
{
    ByteArrayInputStream in = new ByteArrayInputStream(content);

    // Create stream to compress data and write it to the to file.
    GZIPOutputStream gzipOutputStream = null;
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    try
    {
        gzipOutputStream = new GZIPOutputStream(byteArrayOutputStream);
        byte[] buffer = new byte[4096];
        int bytes_read;
        while ((bytes_read = in.read(buffer)) != END_OF_FILE)
        {
            gzipOutputStream.write(buffer, 0, bytes_read);
        }

        // Return the gzipped content
        return byteArrayOutputStream.toByteArray();
    }
    catch (IOException e)
    {   
        // Altered from original to make this a SSCCE
        // Don't write exception handling like this at home!
        System.err.println("Unable to gzip content" + e.getMessage());
        return null;
    }
    /* 
     * Lots of closing streams with exception handling below.
     * I *think* I'm closing off streams in the right order
     * It's not triggering any of the System.err.println calls in any case
     * Of course System.err.println is bad, but this is a SSCCE
     */
    finally
    {
        try 
        {
            if (in != null)
            {
                in.close();
            }
        }
        catch (IOException e)
        {
            System.err.println("Was unable to close the Inputstream for gzipping, be aware of mem leak.");
        }
        try 
        {
            if (byteArrayOutputStream != null)
            {
                byteArrayOutputStream.close();
                if (gzipOutputStream != null)
                {
                    gzipOutputStream.close();
                }
            }
        }
        catch (IOException e)
        {
            System.err.println("Was unable to close the OutputStream(s) for gzipping, be aware of mem leak.");
        }
    }
}

Необработанное содержимое («Содержимое») в байтах:

0x750x6E0x630x6F0x6D0x700x720x650x730x730x650x640x430x6F0x6E0x740x650x6E0x74

Заархивированное содержимое («Содержимое») в байтах:

0x1F0x8B0x080x000x000x000x000x000x000x00

Или альтернативно:

1f8b 0800 0000 0000 0000 

Эквивалентное сжатое содержимое, записанное с использованием GZIPOutputStream и FileOutputStream в локальную файловую систему.

1f8b 0800 0000 0000 0000 2bcd 4bce cf2d  ..........+ÍKÎÏ-
284a 2d2e 4e4d 71ce cf2b 49cd 2b01 00f8  (J-.NMqÎÏ+IÍ+..ø
3987 5f13 0000 00                        9._....

Я думаю, что вижупроблема.Несмотря на то, что содержимое упаковано должным образом, я не создал суффикс контрольной суммы, который требуется для файлов gzip (что GZIPOutputStream делает вместе с FileOutputStream, если вы делаете это в локальной файловой системе).В общем, мне не хватает этого:

2bcd 4bce cf2d  ..........+ÍKÎÏ-
284a 2d2e 4e4d 71ce cf2b 49cd 2b01 00f8  (J-.NMqÎÏ+IÍ+..ø
3987 5f13 0000 00                        9._....

Я не вижу метода в библиотеке Jsch, который бы справился с этим - а это означает, что я думаю, что упускаю какой-то фундаментальный момент.

1 Ответ

7 голосов
/ 04 июня 2011

Похоже, что ваша проблема в использовании GZipOutputStream в сочетании с ByteArrayOutputStream и полностью не связанном с JSch.

GZipOutputStream использует (по своему суперклассу, DeflatorOutputStream) Deflator для выполнения фактической работы. Этому дефлятору разрешено буферизовать любой объем данных, который он сочтет целесообразным, пока вы не используете его метод finish() (потоками finish() или close()), чтобы сообщить, что сжатый файл завершен. Затем он также записывает нижний колонтитул gzip, включая контрольную сумму, в выходной файл назначения.

Я думаю, что ваша проблема может быть решена либо перемещением getByteArray после вашего close() каскада, либо добавлением finish() перед ним.

...