大文件下载如何优化?

想用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一下你的代码实现,可以直观看出来哪里有优化空间