简体   繁体   English

如何在不解压缩的情况下通过 SFTP (Jsch) 编写压缩字节数组?

[英]How do I write a gzipped byte array via SFTP (Jsch) without decompressing it?

(This was x-posted to the Jsch mailing list BTW). (这是 x-posted 到 Jsch 邮件列表 BTW)。 I'm reading data from a database and carrying that as a byte[] (for transportation across middleware components).我正在从数据库中读取数据并将其作为 byte[] 进行传输(用于跨中间件组件传输)。

From that byte[] I know how to create a gzipped file on the local file system by using the GZIPOutputStream class. Want I want to do is create a gzipped file on a remote file system by using the JSch SFTP methods.从那个 byte[] 我知道如何使用 GZIPOutputStream class 在本地文件系统上创建一个 gzip 文件。我想做的是使用 JSch SFTP 方法在远程文件系统上创建一个 gzip 文件。

I've gzipped the byte[] of data and am passing that as an InputStream to the JSch library for SFTPing to a remote file directory (as a.gz file).我已经压缩了数据的 byte[] 并将其作为 InputStream 传递给 JSch 库,以便 SFTPing 到远程文件目录(作为 a.gz 文件)。 However, the file that is delivered has an unexpected EOF and cannot be 'gunzipped'但是,传送的文件有一个意外的 EOF 并且不能被“gunzipped”

gunzip: GlobalIssuer.xml.gz: unexpected end of file gunzip:GlobalIssuer.xml.gz:文件意外结束

Reminder I'm not transferring a byte[] that is the contents of a.gz file, it's the contents of a database record提醒我传输的不是 a.gz 文件内容的 byte[],它是数据库记录的内容

The (relatively) SSCCE is as follows: (相对)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");

The gzipContent method: 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.");
        }
    }
}

The raw content ("Content") in bytes:以字节为单位的原始内容(“内容”):

0x750x6E0x630x6F0x6D0x700x720x650x730x730x650x640x430x6F0x6E0x740x650x6E0x74

The gzipped content ("Content") in bytes:以字节为单位的压缩内容(“内容”):

0x1F0x8B0x080x000x000x000x000x000x000x00

Or alterantively:或者换句话说:

1f8b 0800 0000 0000 0000 

The equivalent gzipped content written out using the GZIPOutputStream and FileOutputStream to the local file system.使用 GZIPOutputStream 和 FileOutputStream 写入本地文件系统的等效 gzip 内容。

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._....

I think I see the problem.我想我看到了问题。 Although the content is gzipped properly, I haven't created the checksum suffix that gzipped files require (which the GZIPOutputStream does do in conjunction with the FileOutputStream if you're doing this on a local file system).虽然内容已正确压缩,但我还没有创建压缩文件所需的校验和后缀(如果您在本地文件系统上执行此操作,GZIPOutputStream 会与 FileOutputStream 一起执行)。 So basically I'm missing this:所以基本上我错过了这个:

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

I can't see a method in the Jsch library that would do the trick - which means I think I'm missing some fundamental point.我在 Jsch 库中看不到可以解决问题的方法——这意味着我认为我遗漏了一些基本要点。

It looks like your problem is in the usage of the GZipOutputStream combined with the ByteArrayOutputStream, and totally unrelated to JSch.看起来您的问题在于 GZipOutputStream 与 ByteArrayOutputStream 的结合使用,与 JSch 完全无关。

GZipOutputStream is using (by its superclass, a DeflatorOutputStream) a Deflator to do the actual work. GZipOutputStream 使用(通过其超类 DeflatorOutputStream)一个 Deflator 来完成实际工作。 This deflator is allowed to buffer any amount of data it deems appropriate, until you use its finish() method (either by the streams finish() or close() ) to say that the compressed file is finished.允许此 deflator 缓冲它认为合适的任何数据量,直到您使用它的finish()方法(通过流finish()close() )表明压缩文件已完成。 This then also writes the gzip footer including the checksum to the destination output.然后,这还将包含校验和的gzip页脚写入目标 output。

I think your problem could be solved by either moving the getByteArray after your close() cascade, or adding a finish() before it.我认为您的问题可以通过在close()级联之后移动getByteArray或在其之前添加finish()来解决。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM