Download videos in binary mode

1. Requirements: The front desk calls the background download video interface multiple times through multithreading to download a video with a large memory in a short time.
2. Implementation principle:
1. When downloading the video, the front desk will create a temporary file of the total size of the original video, and then start multi-threading. Each thread downloads a video segment, and each downloaded video segment will be filled in the temporary file. Specify the location. So the parameters required by this method are: sliceOffset the position of the sliced ​​video; sliceSize the size of each sliced ​​video.
2. Input stream:

            FileInputStream fis = new FileInputStream(file);
			fis.skip(sliceOffset);//从指定位置读取字节
			InputStream bis = new BufferedInputStream(fis);//输入流

Output stream:

		OutputStream toClient = new BufferedOutputStream(response.getOutputStream());//输出流
			response.reset();//清除首部空白行
			response.setContentType("application/octet-stream");//设置客户端接收的数据类型,这里是 二进制
			response.setContentLength(sliceSize);//输出长度

The specific code is as follows:

1. Control layer

@PostMapping(value = "downloadVideoSlice")
	public ServerResponse<?> downloadVideoSlice(HttpServletRequest request, HttpServletResponse response) {
    
    
		Integer stAutoId = Integer.parseInt(request.getParameter("stAutoId"));
		Integer iId = Integer.parseInt(request.getParameter("iId"));
		Integer sliceOffset = Integer.parseInt(request.getParameter("sliceOffset"));
		Integer sliceSize = Integer.parseInt(request.getParameter("sliceSize"));
		String path = (String) iImageService.downloadVideoSlice(stAutoId, iId).getData();
		// 将文件转化成流输出
		FileUtil.getOutputStream(path, response, sliceOffset, sliceSize);
		return null;
	}

2. Implementation class (involving business, you can ignore this part)

@Override
	public ServerResponse<?> downloadVideoSlice(int stAutoId, int iId) {
    
    
		Tstudy tstudy = tstudyMapper.selectByPrimaryKey((long) stAutoId);
		Date stDate = tstudy.getStStartdate();
		String stDate_str = DateTimeUtil.dateToStr(stDate, "yyyy-MM-dd HH:mm:ss");
		VStorageNodeMethod method = CommonConfigCache.getVStorageNodeMethodByDate(stDate, tstudy.getStHospitalcode(),
				StorageNodeType.IMAGE, StorageMethodType.DOWNLOAD, Method.HTTP.getType());
		String httpHead = method.getSmnHttpVirtualPath();
		String rootPath = method.getSnRootpath();

		if (method == null) {
    
    
			return ServerResponse.createByErrorMessage("查无此图");
		}
		// 获取图片表
		String stDate_str1 = DateTimeUtil.dateToStr(stDate, "yyyyMMdd");

		Timagecontrol timagecontrol = CommonConfigCache.getTimagecontrol("US", stDate_str1);

		TimageExample timageExample = new TimageExample();
		timageExample.createCriteria().andIIdEqualTo((long) iId);
		timageExample.setOrderByClause("I_Number");
		List<Timage> timages = timageMapper.selectByExampleWithTableName(timagecontrol.getcImagetablename(),
				timageExample);
		Timage timage = null;
		if (CollectionUtils.isNotEmpty(timages) && timages.size() > 0) {
    
    
			timage = timages.get(0);
		}
		String serverpath = timage.getiServerpath();
		String filePath = rootPath + serverpath.replace("/", "\\");
		return ServerResponse.createBySuccess(filePath);
	}

3. Tools (focus)

Http ContentTpye comparison table

/**
	 * 将文件转化成流输出
	 * 
	 * @param path
	 * @param response
	 * @param sliceOffset
	 * @param sliceSize
	 */
	public static void getOutputStream(String path, HttpServletResponse response, Integer sliceOffset,
			Integer sliceSize) {
    
    

		File file = new File(path);
		try {
    
    
			FileInputStream fis = new FileInputStream(file);
			fis.skip(sliceOffset);//从指定位置读取字节
			InputStream bis = new BufferedInputStream(fis);//输入流
			OutputStream toClient = new BufferedOutputStream(response.getOutputStream());//输出流
			response.reset();//清除首部空白行
			response.setContentType("application/octet-stream");//设置客户端接收的数据类型,这里是 二进制
			response.setContentLength(sliceSize);//输出长度
			// 数据缓冲区
			byte[] arr = new byte[1024];
			int len;
			long count = 0;
			// 数据读写
			while ((len = bis.read(arr)) != -1) {
    
    
				// 分三种情况
				if (len + count > sliceSize) {
    
    
					// 1.当读取的时候操作自己该线程的下载总量的时候,需要改变len
					len = (int) (sliceSize - count);
					toClient.write(arr, 0, len);
					// 证明该线程下载任务已经完毕,结束读写操作
					break;
				} else if (len + count < sliceSize) {
    
    
					// 2.证明还没有到下载总量,直接将内容写入
					toClient.write(arr, 0, len);
					// 并且使计数器任务累加
					count += arr.length;
				} else {
    
    
					// 3.证明改好到下载总量
					toClient.write(arr, 0, len);
					// 结束读写
					break;
				}
			}
			toClient.close();
			bis.close();
			fis.close();
		} catch (FileNotFoundException e) {
    
    
			e.printStackTrace();
		} catch (IOException e) {
    
    
			e.printStackTrace();
		}

	} ```

Guess you like

Origin blog.csdn.net/weixin_44215804/article/details/109449233