斷點續傳文件

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.catalina.connector.ClientAbortException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Title: IndexController.java
 * @Package com.fhhr.controller
 * @Description:
 * @author ybwei
 * @date 2018年9月10日 下午12:11:04
 * @version V1.0
 */
@RestController
public class IndexController {
	private final Logger logger = LoggerFactory.getLogger(getClass());

	@Value("${file.download.path}")
	private String filePathName;

	/**
	 * 斷點下載
	 * @param request
	 * @param response
	 * @param range
	 * @author ybwei
	 */
	@RequestMapping("/downloadFile")
	public void home(HttpServletRequest request, HttpServletResponse response,
			@RequestHeader(required = false) String range) {
		// 文件目錄
		File file = new File(filePathName);

		// 開始下載位置
		long startByte = 0;
		// 結束下載位置
		long endByte = file.length() - 1;

		// 有range的話
		if (range != null && range.contains("bytes=") && range.contains("-")) {
			range = range.substring(range.lastIndexOf("=") + 1).trim();
			String ranges[] = range.split("-");
			try {
				// 判斷range的類型
				if (ranges.length == 1) {
					// 類型一:bytes=-2343
					if (range.startsWith("-")) {
						endByte = Long.parseLong(ranges[0]);
					}
					// 類型二:bytes=2343-
					else if (range.endsWith("-")) {
						startByte = Long.parseLong(ranges[0]);
					}
				}
				// 類型三:bytes=22-2343
				else if (ranges.length == 2) {
					startByte = Long.parseLong(ranges[0]);
					endByte = Long.parseLong(ranges[1]);
				}

			} catch (NumberFormatException e) {
				startByte = 0;
				endByte = file.length() - 1;
			}
		}

		// 要下載的長度(爲啥要加一問小學數學老師去)
		long contentLength = endByte - startByte + 1;
		// 文件名
		String fileName = file.getName();
		// 文件類型
		String contentType = request.getServletContext().getMimeType(fileName);

		// 解析斷點續傳相關信息
		response.setHeader("Accept-Ranges", "bytes");
		// 若客戶端傳來Range,說明以前下載了一部分,設置206狀態(SC_PARTIAL_CONTENT)
		response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
		response.setContentType(contentType);
		response.setHeader("Content-Type", contentType);
		// 這裏文件名換你想要的,inline表示瀏覽器直接實用(我方便測試用的)
		// 參考資料:http://hw1287789687.iteye.com/blog/2188500
		response.setHeader("Content-Disposition", "attachment;filename=" + file.getName());
		response.setHeader("Content-Length", String.valueOf(contentLength));
		// [要下載的開始位置]-[結束位置]/[文件總大小]
		response.setHeader("Content-Range", "bytes " + startByte + "-" + endByte + "/" + file.length());

		BufferedOutputStream outputStream = null;
		RandomAccessFile randomAccessFile = null;
		// 已傳送數據大小
		long transmitted = 0;
		try {
			randomAccessFile = new RandomAccessFile(file, "r");
			outputStream = new BufferedOutputStream(response.getOutputStream());
			byte[] buff = new byte[4096];
			int len = 0;
			randomAccessFile.seek(startByte);
			// contentLength)要放前面!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
			// 否則會會先讀取randomAccessFile,形成後面讀取位置出錯,找了一天才發現問題所在
			while ((transmitted + len) <= contentLength && (len = randomAccessFile.read(buff)) != -1) {
				outputStream.write(buff, 0, len);
				transmitted += len;
			}
			// 處理不足buff.length部分
			if (transmitted < contentLength) {
				len = randomAccessFile.read(buff, 0, (int) (contentLength - transmitted));
				outputStream.write(buff, 0, len);
				transmitted += len;
			}

			outputStream.flush();
			response.flushBuffer();
			randomAccessFile.close();
			logger.info("下載完畢:" + startByte + "-" + endByte + ":" + transmitted);

		} catch (ClientAbortException e) {
			logger.info("用戶中止下載:" + startByte + "-" + endByte + ":" + transmitted);
			// 捕獲此異常表示擁護中止下載
		} catch (IOException e) {
			logger.info("下載異常:", e);
		} finally {
			try {
				if (randomAccessFile != null) {
					randomAccessFile.close();
				}
			} catch (IOException e) {
				logger.info("下載異常:", e);
			}
		}

	}

}
相關文章
相關標籤/搜索