使用播放框架和第三方API流式处理大文件

我正在编写一个play 2应用程序,我正在努力解决文件流问题。 我使用具有以下签名的方法使用第三方API检索我的文件:

FileMetadata getFile(OutputStream destination, String fileId)

在传统的Servlet应用程序中,如果我想将内容发送给我的客户端,我会做类似如下的事情:

HttpServletResponse resp;
myService.getFile(resp.getOutpuStream, fileId);

我的问题是,在我玩2控制器类我没有访问底层的OuputStream,所以我的控制器方法最简单的实现将是:

public static downloadFile(String id) {
    ByteArrayOutputStream baos = new BAOS(...);
    myApi.getFile(baos,id); //Load inside temp Array      
    ByteArrayInputStream bais = new BAIS(baos.toByteArray())
    return Ok(bais);
 }

它会工作,但它需要将全部内容加载到内存中才能使用它,因此它不是一个选项(文件可能很大)。

我想到的解决方案包括:

  • 在我的控制器中定义一个ByteArrayOutputStream(baos)
  • 在参数中使用这个baos调用第三方API
  • 只要第三方API写入内容,就可以使用play框架的块返回来发送baos的内容
  • 问题是我不知道是否有可能(调用getFile进行阻塞,因此它需要多个具有共享OutputStream的线程),也不会过度。

    正如有人遇到过这样的问题并找到了解决方案? 我的建议解决方案能解决我的问题吗

    任何见解将不胜感激。

    谢谢

    编辑1基于kheraud的建议,我设法有一个工作,但仍不完美的解决方案(代码如下)。

    不幸的是,如果在调用getFile方法期间发生问题,错误不会发回给客户端(因为我返回Ok),浏览器将无限期地等待一个永远不会到来的文件。

    有办法处理这种情况吗?

    public static Result downloadFile(String fileId {    
          Thread readerThread = null;
          try {
              PipedOutputStream pos = new PipedOutputStream();
              PipedInputStream pis = new PipedInputStream(pos); 
              //Reading must be done in another thread
              readerThread = new DownloadFileWorker(fileId,pos);
              readerThread.start();
    
              return ok(pis);
          } catch (Exception ex) {
              ex.printStackTrace();
              return internalServerError(ex.toString());
    
          }
      }
    
    static class DownloadFileWorker extends Thread{
          String fileId;  
          PipedOutputStream pos;
    
          public DownloadFileWorker(String fileId, PipedOutputStream pos) {
            super();
            this.fileId = fileId
            this.pos = pos;
        }
    
        public void run(){
              try {
                  myApi.getFile(pos,fileId);
                  pos.close();
              } catch (Exception ex) {
                  ex.printStackTrace();
              }
          }
    }
    

    编辑2

    我找到了一种方法,只需在工作线程的catch()部分中添加一个pos.close,就可以避免无限加载页面。 客户端以零KB文件结束,但我想这比无限等待更好。


    Play2 Scala框架中为此提供了一些东西: Enumerators 。 这与您所想的非常接近。

    你应该看看这个文档页面的细节

    我在Play2 Java API中没有找到类似的东西,但是在fw代码源中,您有一个:

    public static Results.Status ok(java.io.InputStream content, int chunkSize)
    

    接缝的方法就是你要找的。 该实现可以在play.mvc.Resultsplay.core.j.JavaResults类中找到。


    在游戏中! 邮件列表,最近有一个关于同一主题的讨论:

    https://groups.google.com/forum/#!topic/play-framework/YunJzgxPKsU/discussion

    它包含一个允许非Scala识字的小片段(比如我自己)使用Play!的scala流媒体界面。

    链接地址: http://www.djcxy.com/p/11057.html

    上一篇: Streaming large files with play framework and third party API

    下一篇: How to search in freebase by mid