使用Java恢复失败的压缩

时间:2010-07-28 03:40:30

标签: java networking compression

我有一个很小的数字(2-10)的大文件(6-15GB)压缩得非常好(4:1)。

我用Java编写客户端和服务器,我想将文件从客户端发送到服务器,以便  1.客户端在发送文件时压缩文件(即没有创建中间.zip文件)
 2.服务器上的压缩内容最终形成一个格式良好的文件(例如.zip或.tgz文件),以便可以“按原样”下载。
 3.如果转移中途失败,转移可以恢复  4.恢复转移可能完全在一个新的过程中发生

使用java.io套接字和java.util.zip ZipOutputStreams可以很容易地实现前两个。第三个是导致我悲伤的那个。第四个真的只是背景。

我猜测解决方案可能需要某种部分重新传输或重新解析才能建立字典或其他内容。

是否有支持可恢复压缩的Java库?

3 个答案:

答案 0 :(得分:2)

我找不到任何以我需要的方式支持可恢复压缩的预制库。但是,在开放许可证下可以使用许多可用的零件来编写自己的零件。我现在有一个客户端/服务器解决方案,可以满足问题中列出的所有限制。

这个想法类似于上面概述的分块思想,但是服务器管理分块并进行一些记录,将客户端上的压缩块映射到服务器上的压缩块。解决方案中的任何位置都没有临时文件。基本协议如下

(1) The client sends a manifest to the server, containing the
    to-be contents of the zip file  
(2) The server sends back an ID for the manifest  
    Then repeatedly  
  (3) The client asks the server "is there anything still 
      required for the manifest with ID X"
  (4) The server replies "no", or with a manifest entry 
      for a file in the manifest, plus a offset and length to send
  (5) The client compresses that chunk and sends it (plus some 
       bookkeeping info)
  (6) The server puts the chunk into the every growing zip file, 
      plus appropriate zip file crud. If the server orders 
      the chunks it asks the client for appropriately, this can 
      all be done by file appends.

服务器仅在步骤6成功完成时更新清单,因此步骤3-6中的故障(包括服务器或客户端上的崩溃)可以安全地恢复(好吧,或多或少)。

在创建chunk-wise zip文件时有一些小问题。需要实现的基本功能是找到一个可以块化的压缩算法。可以这种方式使用Deflate。

java ZipOutputStream和DeflaterOutputStream不适合'chunk-wise'通缩/压缩,因为它们不允许任意刷新。在http://www.jcraft.com/jzlib有一个BSL风格的ZLib许可Java实现。我没有为速度进行基准测试,但是它提供了与Java实现相同的输出。 JZLib很棒,并且支持ZLib的所有刷新模式(与java.util.zip.Deflate实现不同)。

此外,Zip文件为每个条目计算CRC。因此,步骤4中的清单条目包含一个“部分”CRC,每个块都会更新并在步骤5中的簿记信息中发回。在http://www.axlradius.com/freestuff/CRC32.java处有一个用于java的CRC的公共域实现。我对它进行了基准测试,它与本机java实现一样快(并提供了等效的CRC)。

最后,Zip文件格式非常不稳定。我设法将维基百科页面和http://www.pkware.com/documents/casestudies/APPNOTE.TXT中的大多数实现拼凑在一起。虽然在某一点上我无法为其中一个字段工作正确的值。幸运的是,JDK的ZipOutputStream源可用,因此您可以看到它们的功能。

答案 1 :(得分:0)

我不知道任何可以让你在流中间恢复压缩的东西;这似乎是一个非常敏感的事情。

相反,您可能会考虑将文件“分解”为较小的块并单独发送(使用压缩)。比方说,100kb块(例如)。你仍然无法在一个块的中间恢复,但你可以很容易地从最近的块开始。

答案 2 :(得分:0)

即时压缩很容易。您将遇到的问题是恢复上传。这基本上消除了HTTP作为传输,因此您需要查看类似(S)FTP或SCP的内容。即使存在问题,你是不是在客户端上创建一个文件,那么将会恢复什么?至少,您需要使用一种确定性的压缩方法(意味着给定一个指定的文件,压缩算法的任何两次运行都会产生完全相同的输出)。如果不是这样,则无法恢复

我的建议是采取略微切向的方法。将文件划分为可管理的块(比如说50MB)。这是确定性的。单独压缩每个块。如果块失败,请重新发送。没有恢复,但您可以通过服务器获得部分上传,告诉客户端收到或等待的是什么块。

您将遇到的一个问题是识别特定文件。文件名会吗?还有其他识别特征吗?如果两个客户端尝试上传相同的文件,服务器是否能够检测到这个?这类事情的标准方法是使用校验和(文件内容的SHA1哈希),但您不想完整地读取16GB文件来执行校验和。所以其他一些方法更可取。

想象一下网络通信是这样的:

Client: SEND file1234 CHUNKS 167
Server: RECEIVED (already got) or WAIT 7 (chunk #)
Client: compress and send chunk 7
Server: WAIT 8
....

此方法还将处理多个客户端同时上传文件,因为服务器可以从不同的客户端请求不同的块并将它们合并在一起。

这个方法的一个问题是服务器上的文件不是“完整”(作为zip或tarball)但是我认为你需要放弃一些实际上工作的东西而不是编码的噩梦。