乐趣区

java-播放视屏文件分片加载

文件分片播放,方便测试工具代码如下:

import org.apache.catalina.connector.ClientAbortException;

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.RequestHeader;

import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import java.io.BufferedOutputStream;

import java.io.File;

import java.io.IOException;

import java.io.RandomAccessFile;

@Controller

@RequestMapping(value = “/upload/main/”)

public class Main {

@RequestMapping(“test/{name}/{hz}”)

public void home(@PathVariable(“name”) String name, @PathVariable(“hz”) String hz, HttpServletRequest request,

HttpServletResponse response, @RequestHeader(required = false) String range) {

// 文件位置

File music = new File(“D:\\Temp\\patch\\2020-04-14\\” + name + “.” + hz);

// 开始下载位置

long startByte = 0;

// 结束下载位置

long endByte = music.length() – 1;

// 有 range 的话

if (range != null && range.contains(“bytes=”) && range.contains(“-“)) {

// 坑爹地方一:http 状态码要为 206

response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);

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 = music.length() – 1;

}

} else {

// 没有 ranges 即全部一次性传输,需要用 200 状态码,这一行应该可以省掉,因为默认返回是 200 状态码

response.setStatus(HttpServletResponse.SC_OK);

}

// 要下载的长度(endByte 为总长度 -1,这时候要加回去)

long contentLength = endByte – startByte + 1;

// 文件名

String fileName = music.getName();

// 文件类型

String contentType = request.getServletContext().getMimeType(fileName);

// 各种响应头设置

// 参考资料:https://www.ibm.com/developer…

// 坑爹地方二:看代码

response.setHeader(“Accept-Ranges”, “bytes”);

response.setContentType(contentType);

response.setHeader(“Content-Type”, contentType);

// 这里文件名换你想要的,inline 表示浏览器可以直接使用(比如播放音乐,我方便测试用的)

// 参考资料:http://hw1287789687.iteye.com…

response.setHeader(“Content-Disposition”, “inline;filename=test.mp4”);

response.setHeader(“Content-Length”, String.valueOf(contentLength));

// 坑爹地方三:Content-Range,格式为

// [要下载的开始位置]-[结束位置]/[文件总大小]
外汇隔夜利息 http://www.fx61.com/interest….

response.setHeader(“Content-Range”, “bytes ” + startByte + “-” + endByte + “/” + music.length());

BufferedOutputStream outputStream = null;

RandomAccessFile randomAccessFile = null;

// 已传送数据大小

long transmitted = 0;

try {

randomAccessFile = new RandomAccessFile(music, “r”);

outputStream = new BufferedOutputStream(response.getOutputStream());

byte[] buff = new byte[4096];

int len = 0;

randomAccessFile.seek(startByte);

// 坑爹地方四:判断是否到了最后不足 4096(buff 的 length)个 byte 这个逻辑 ((transmitted + len) <= contentLength) 要放前面!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

// 不然会先读取 randomAccessFile,造成后面读取位置出错,找了一天才发现问题所在

while ((transmitted + len) <= contentLength && (len = randomAccessFile.read(buff)) != -1) {

outputStream.write(buff, 0, len);

transmitted += len;

// 停一下,方便测试(本地下载传输速度特别快,没反应过来就下载好了),实际生产环境中用的时候需要删除这一行

Thread.sleep(10);

}

// 处理不足 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();

System.out.println(“ 下载完毕:” + startByte + “-” + endByte + “:” + transmitted);

} catch (ClientAbortException e) {

System.out.println(“ 用户停止下载:” + startByte + “-” + endByte + “:” + transmitted);

// 捕获此异常表示拥护停止下载

} catch (IOException | InterruptedException e) {

e.printStackTrace();

} finally {

try {

if (randomAccessFile != null) {

randomAccessFile.close();

}

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

退出移动版