Потоковая передача больших файлов с помощью play framework и стороннего API

Я пишу приложение play 2 и борюсь с проблемой потоковой передачи файлов. Я получаю свои файлы с помощью стороннего API с помощью метода, имеющего следующую сигнатуру:

FileMetadata getFile(OutputStream destination, String fileId)

В традиционном приложении Servlet, если бы я хотел отправить содержимое своему клиенту, я бы сделал что-то вроде:

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

Моя проблема в том, что в моем классе контроллера play 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 )внутри моего контроллера
  • Вызов стороннего API с этим баосом в параметре
  • Использование возврата фрагмента игровой платформы для отправки содержимого baos, как только что-то написано внутри сторонним API

Проблема в том, что я не знаю, возможно ли, что (вызов 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

Я нашел способ избежать бесконечной загрузки страницы, просто добавив pos.close в часть catch ()рабочего потока. Клиент получает файл с нулевым КБ, но я думаю, что это лучше, чем бесконечное ожидание.

7
задан Davz 8 August 2012 в 12:36
поделиться