我可以在vaadin中直接传输ZipFile吗?

时间:2016-04-15 10:13:57

标签: java vaadin

我的应用程序的当前架构不允许我在服务器端存储文件并创建指向该存储文件的链接。那么有没有其他选项(或代码片段)直接流ZipFile并将其存储在客户端?

修改: 我想我的问题被误解了。我收到压缩文件的答案并将其存储在客户端。我已经实现了这一点。以下是示例用例的主要关注点:

方案: 用户有大约5000条记录(每条大约1 MB),并且用户希望下载以ZIP格式压缩的每5000条记录的子记录(CSV格式)。所有CSV文件都是即时生成的。

方法: 由于ZIP文件的大小可以达到5 GB,因此我采用了将文件内容直接流式传输到客户端创建的ZIP文件的方法。我已经使用了PipeInputStream和PipeOutputStream。

结果: 由于我是vaadin的新手,我在上述方法中没有成功,因此寻找任何建议/代码片段,支持将ZIP文件(无论大小如何)直接流式传输到客户端。

我想我现在很清楚。

5 个答案:

答案 0 :(得分:3)

您的问题不明确。总是,在发布问题时提供一些研究。现在,问题是你要从哪里流式传输一些URL,Fileshare,Database。您正在使用的Vaadin版本6<或> 6?

已编辑问题分为两部分。

  1. 直接从网站下载Zip文件。以下是用于下载任何文件的示例代码段。

    import java.io.BufferedInputStream;
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.InputStream;
    import java.net.URL;
    
    import javax.servlet.annotation.WebServlet;
    
    import com.vaadin.annotations.Theme;
    import com.vaadin.annotations.VaadinServletConfiguration;
    import com.vaadin.server.FileDownloader;
    import com.vaadin.server.StreamResource;
    import com.vaadin.server.StreamResource.StreamSource;
    import com.vaadin.server.VaadinRequest;
    import com.vaadin.server.VaadinServlet;
    import com.vaadin.ui.Button;
    import com.vaadin.ui.UI;
    
    @SuppressWarnings("serial")
    @Theme("vaadintest")
    public class VaadintestUI extends UI {
    
        @WebServlet(value = "/*", asyncSupported = true)
        @VaadinServletConfiguration(productionMode = false, ui = VaadintestUI.class)
        public static class Servlet extends VaadinServlet {
        }
    
        protected void init(VaadinRequest request) {
            Button downloadButton = new Button("Download Zip File");
    
            StreamResource myResource = createResource();
            FileDownloader fileDownloader = new FileDownloader(myResource);
            fileDownloader.extend(downloadButton);
    
            setContent(downloadButton);
        }
    
    private StreamResource createResource() {
        return new StreamResource(new StreamSource() {
            @Override
            public InputStream getStream() {
    
                BufferedInputStream in = null;
                ByteArrayOutputStream bao = null;
                try {
                    in = new BufferedInputStream(
                            new URL("http://www-us.apache.org/dist/commons/io/binaries/commons-io-2.5-bin.zip" + "")
                                    .openStream());
                    byte[] buff = new byte[8000];
                    int bytesRead = 0;
                    bao = new ByteArrayOutputStream();
    
                    while ((bytesRead = in.read(buff)) != -1) {
                        bao.write(buff, 0, bytesRead);
                    }
    
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return new ByteArrayInputStream(bao.toByteArray());
    
            }
        }, "somefile.zip");
    }
    

    }

  2. 压缩巨大的CSV文件并下载

  3. 参考:Best Practices to Create and Download a huge ZIP (from several BLOBs) in a WebApp

    在服务器端进行压缩和存储很容易。我不认为由于访问问题而直接存储到客户端磁盘会更容易(可以使用OutputStream)。您可以在服务器端压缩它并共享链接到压缩文件的客户端(文件需要存储在WebApp文件夹中)。

    另外,你可以在压缩后使用输出流来下载它.Below就是它的简单例子。

    参考:http://www.mkyong.com/java/how-to-download-file-from-website-java-jsp/

    编辑问题,提供实际方案:然后分享代码段很容易

    您可以参考的一些有用链接如下:

    1. Best Practices to Create and Download a huge ZIP (from several BLOBs) in a WebApp
    2. How to split a huge zip file into multiple volumes?
    3. Zip files with Java: Is there a limit?
    4. Very large zip file (> 50GB) --> ZipException: invalid CEN header
    5. Java multithreaded file downloading performance
    6. In Java: How to zip file from byte[] array?
    7. Uncompressing a ZIP file in memory in Java
    8. Best way to detect if a stream is zipped in Java

答案 1 :(得分:2)

我可以看到答案已被系统自动接受(不是由我),因为它被投票了3次。我没有问题,但我不想混淆那些(以防万一)在这里寻找答案的人。我很欣赏@Pratyush Kumar Singh给出的答案(因为它可以帮助你探索更多)但是抱歉 StackOverFlow 我无法接受答案,因为我的问题没有得到解答但 即可。我仍在努力,一旦通过POC解决,我将发布答案。

答案 2 :(得分:2)

Java JDK和Apache commons-compress不允许您懒惰地流式传输ZIP存档,因此我实现了Java ZIP库[1]来处理它。目前的限制是它不支持ZIP64扩展,这意味着它无法压缩大于4 GiB的文件,并且无法生成大于4 GiB的存档。我正在努力。

[1] https://github.com/tsabirgaliev/zip

答案 3 :(得分:1)

您不必创建ZIP包来通过HTTP压缩单个文件。所有体面的浏览器都支持读取压缩的HTTP响应[1],所以让我们利用它:

@Theme("mytheme")
@Widgetset("org.test.MyAppWidgetset")
public class MyUI extends UI {

    @Override
    protected void init(VaadinRequest vaadinRequest) {
        Button downloadButton = new Button("Download File");

        StreamResource myResource = createResource();
        FileDownloader fileDownloader = new FileDownloader(myResource);
        fileDownloader.extend(downloadButton);

        setContent(downloadButton);
    }

    private StreamResource createResource() {
        return new StreamResource(new StreamResource.StreamSource() {
            @Override
            public InputStream getStream() {
                InputStream s = null;
                try {
                    s = new DeflaterInputStream(new FileInputStream("/tmp/some.csv"));
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
                return s;

            }
        }, "some.csv") {
            @Override
            public DownloadStream getStream() {
                DownloadStream ds =  super.getStream();
                ds.setParameter("Content-Encoding", "deflate");
                return ds;
            }
        };
    }

    @WebServlet(urlPatterns = "/*", name = "MyUIServlet", asyncSupported = true)
    @VaadinServletConfiguration(ui = MyUI.class, productionMode = false)
    public static class MyUIServlet extends VaadinServlet {
    }
}

浏览器将下载压缩流,但保存原始文件,即时解压缩。

优点:这非常节省内存。

缺点:您无法将多个文件合并到一个ZIP存档中。

[1] https://en.wikipedia.org/wiki/HTTP_compression

答案 4 :(得分:0)

看起来像apache.commons.compress ZipArchiveOutputStream就是你问题的答案。但是你应该知道你的情况存在一系列限制(没有RandomAccessFile)。简单示例(使用stdout重定向:java -cp Test> test.zip):

import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
import java.util.Arrays;

public class Test {

public static void main(String[] args) throws Exception {
      ZipArchiveOutputStream zipOut = new ZipArchiveOutputStream(System.out);
      byte[] data = new byte[1024*1024];
      for(byte i=49; i<120; i++) {
          Arrays.fill(data, i);
          ArchiveEntry file1 = new ZipArchiveEntry("file" + i + ".txt");
          zipOut.putArchiveEntry(file1);
          zipOut.write(data);
          zipOut.closeArchiveEntry();
       }
       zipOut.finish();
       zipOut.close();
    }
}