如何通过 Spring-Feign 获取 InputStream?

dgr*_*ory 4 java zero-copy spring-boot spring-cloud-feign feign

我想通过 Spring-OpenFeign 从服务器下载一个文件并将其保存在本地目录中,并使用零拷贝。

简单的下载方法如下:

import org.apache.commons.io.FileUtils

@GetMapping("/api/v1/files")
ResponseEntity<byte[]> getFile(@RequestParam(value = "key") String key) {
    ResponseEntity<byte[]> resp = getFile("filename.txt")
    File fs = new File("/opt/test")
    FileUtils.write(file, resp.getBody())
}
Run Code Online (Sandbox Code Playgroud)

在这段代码中,数据流将是这样的 feign Internal Stream -> Buffer -> ByteArray -> Buffer -> File

如何高效快速地下载和保存文件内存?

dgr*_*ory 5

TL;博士。使用ResponseEntity<InputStreamResource>和 Java NIO

根据SpringDecoder,Spring 使用 HttpMessageConverters 解码响应

ResourceHttpMessageConverter 是 HttpMesageConverters 之一,返回InputStreamResource,其中包含 InputStream 和派生自Content-Disposition.

但是,必须初始化 ResourceHttpMessageConvertersupportsReadStreaming = true (default value) 如果您对此实现有进一步的兴趣,请查看此代码

因此,更改后的代码如下:

@GetMapping("/api/v1/files")
ResponseEntity<InputStreamResource> getFile(@RequestParam(value = "key") String key)
Run Code Online (Sandbox Code Playgroud)

JDK9

try (OutputStream os = new FileOutputStream("filename.txt")) {
    responeEntity.getBody().getInputStream().transferTo(os);
}
Run Code Online (Sandbox Code Playgroud)

JDK8 或更少

使用番石榴ByteStreams.copy()

Path p = Paths.get(responseEntity.getFilename())
ReadableByteChannel rbc = Channels.newChannel(responeEntity.getBody().getInputStream())
try(FileChannel fc = FileChannel.open(p, StandardOpenOption.WRITE)) {
    ByteStreams.copy(rbc, fc)
}
Run Code Online (Sandbox Code Playgroud)

现在, Feign Internal Stream -> File