![](/img/trans.png)
[英]How to close the HttpServletResponse OutputStream when sending error
[英]How to avoid this compiler warning to close an OutputStream when using CompletableFuture?
我正在使用CompletableFuture
進行異步操作,以下載文件並通過OutputStream
保存其內容。 以下作品的代碼,但是編譯器給我一個警告,要么使用try-with-resources
或關閉OutputStream
在finally-clause
,但未來在完成后關閉whenComplete
。
碼:
final OutputStream outputStream = Files.newOutputStream(file.toPath());
final String url = "https://example.com/some-download.zip";
final CompletionStage<WSResponse> futureResponse = this.client
.url(url)
.setMethod("GET")
.stream();
futureResponse.thenCompose(res -> {
downloadTask.setTotalBytes(res);
Source<ByteString, ?> responseBody = res.getBodyAsSource();
Sink<ByteString, CompletionStage<akka.Done>> outputWriter =
Sink.foreach(bytes -> {
downloadTask.addReceivedBytes(bytes.size());
System.out.println(downloadTask.getProgressAsString());
outputStream.write(bytes.toArray());
});
return responseBody.runWith(outputWriter, this.materializer);
}).whenComplete((res, error) -> {
try {
outputStream.close();
} catch (final IOException e) {
e.printStackTrace();
}
});
警告:
問題:
當我使用try-with-resources
,由於CompletableFuture
的異步特性不會阻塞,因此程序OutPutStream
在將任何內容寫入文件之前關閉OutPutStream
。
那么,有沒有一種方法可以在CompletionStage
聲明OutputStream
並將其向下傳遞呢?
@AndyTurner在其評論中的建議是正確的。 我只需要稍微調整一下代碼即可使其工作。
我沒有意識到responseBody.runWith()
返回另一個CompletionStage
,因此使用try-with-resources
或finally
在thenComponse
塊中關閉了OutputStream
,所以返回的CompletionStage
(來自responseBody.runWith()
)無法寫入它了。 這導致了錯誤。 因此,我們只需使用.toCompletableFuture().get()
在同一個塊中“同步”處理responseBody.runWith()
.toCompletableFuture().get()
。 這沒問題,因為該塊本身在另一個線程中運行,即保持異步狀態。 由於我們不再返回任何內容,因此我們還需要使用thenAccept
(接受一個Consumer
而不是thenCompose
(接受一個Function
。
final String url = "https://example.com/some-download.zip";
final CompletionStage<WSResponse> futureResponse = this.client
.url(url)
.setMethod("GET")
.stream();
futureResponse
.thenAccept(res -> {
try (OutputStream outputStream = Files.newOutputStream(file.toPath())) {
downloadTask.setTotalBytes(res);
Source<ByteString, ?> responseBody = res.getBodyAsSource();
Sink<ByteString, CompletionStage<akka.Done>> outputWriter =
Sink.foreach(bytes -> {
downloadTask.addReceivedBytes(bytes.size());
System.out.println(downloadTask.getProgressAsString());
outputStream.write(bytes.toArray());
});
responseBody.runWith(outputWriter, this.materializer).toCompletableFuture().get();
} catch (IOException | InterruptedException | ExecutionException e) {
e.printStackTrace();
}
});
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.