想用Java实现从远程文件存储服务器下载3-4GB的大文件。用单一的IO流操作感觉下载效率较低,有什么好的办法能提高下载速率吗
使用缓冲流
可以使用缓冲流提高读取效率 BufferedInputStream
。内存允许的话,加大缓冲区大小。
使用零拷贝技术
FileChannel.transferTo
方法实现了文件直接发送到网卡。省略几次拷贝步骤,也可以提升一点io效率。
demo:
import java.io.IOException;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.http.ContentDisposition;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import lombok.extern.slf4j.Slf4j;
@RestController
@RequestMapping("/test")
@Slf4j
public class TestController {
@GetMapping("/download")
public void download(HttpServletRequest request, HttpServletResponse response) throws IOException {
// 下载的文件3.67 GB
Path file = Paths.get("E:\\电影\\NothingtoLose\\NothingtoLose.mkv"); //
String contentType = Files.probeContentType(file);
if (contentType == null) {
contentType = MediaType.APPLICATION_OCTET_STREAM_VALUE;
}
try (FileChannel fileChannel = FileChannel.open(file)) {
long size = fileChannel.size();
log.info("文件大小: {}", size);
response.setContentType(contentType);
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, ContentDisposition.attachment()
.filename(file.getFileName().toString(), StandardCharsets.UTF_8).build().toString());
response.setContentLengthLong(size);
/**
* transferTo 一次性最多只能处理2147483647字节数据。
* 所以需要多次调用
*/
long position = 0;
while (size > 0) {
long count = fileChannel.transferTo(position, size, Channels.newChannel(response.getOutputStream()));
if (count > 0) {
position += count;
size -= count;
}
}
}
}
}
除了代码因素,影响下载的还有硬件(可以考虑使用固态硬盘),服务器带宽。
这种问题,最好copy一下你的代码实现,可以直观看出来哪里有优化空间