文件切割再合并

总记

在开发过程中,难免会碰到文件上文的问题,遇到文件上传势必会碰到文件体积过大的问题。通常我们的解决办法就是对大文件依据某个单位进行切割,并存储;当然,有些博客在切分完成之后选择生成子文件的方式进行存储;也可以选择将切割完的内容以blob二进制的方式存储在数据库的某一个字段中。本文依照,存储进数据库的方式进行开发。

文件切割

@Override
	public R<List<FileResultDTO>> getStatusByFileIds(String files) {
		R<List<FileResultDTO>> r = new R<List<FileResultDTO>>();
		if(StringUtils.isBlank(files)) {
			r.setMsg("没有文件ID");
			r.setObj(null);
			r.setState("error");
			return r;
		}
		List<FileResultDTO> result = new ArrayList<>();
		List<FileStatusDTO> dtoList = JSONObject.parseArray(files, FileStatusDTO.class); 
		if(null != dtoList) {
			if(dtoList.size()>0) {
				dtoList.stream().forEach(el ->{
					if(null != el.getFileIds()) {
						if(el.getFileIds().size()>0) {
							List<String> fileIds = el.getFileIds().stream().distinct().collect(Collectors.toList());
							List<FileRecord> recordList = contentMapper.getListByFileIds(fileIds);
							List<Integer> idList = recordList.stream().map(FileRecord::getStatus).distinct()
									.collect(Collectors.toList());
							if(1 == idList.size()) {
								
								FileResultDTO dto = new FileResultDTO();
								dto.setId(el.getId());
								if(-1 == idList.get(0)) {
									dto.setStatus(0);
								}else if(0 == idList.get(0)) {
									dto.setStatus(1);
								}else if(1 == idList.get(0)) {
									dto.setStatus(2);
								}
								
								result.add(dto);
							}else if(idList.size()>0){
								FileResultDTO dto = new FileResultDTO();
								dto.setId(el.getId());
								dto.setStatus(1);
								result.add(dto);
							}
						}
					}
				});
			}
		}
		r.setMsg("");
		r.setObj(result);
		r.setState("success");
		return r;
	}

	@Override
	public void synchroInnerByFileId(String id) {
	//查询记录表获取文件记录信息以及文件id
		FileRecord record = recordMapper.selectByPrimaryKey(id);
		FileBasics fileBasicCondition = new FileBasics();
		fileBasicCondition.setFileVersionId(record.getFileId());
		FileBasics el = fileMapper.selectOne(fileBasicCondition);
		try {
			FilePathDTO dto = new FilePathDTO();
			BeanUtils.copyProperties(el, dto);
			dto.setOutPath(el.getOutPath());
			if("dwg".equals(el.getExt().toLowerCase())|| "dxf".equals(el.getExt().toLowerCase())) {
				readfile(el.getFilePath(), dto, id,1,0);
			}else {
				if("0".equals(el.getStatus())) {
					readfile(el.getFilePath(), dto, id,1,0);
				}else if("2".equals(el.getStatus())) {
					if(StringUtils.isNotBlank(el.getOutPath())) {
						if("rvt".equals(el.getExt().toLowerCase()) || "ifc".equals(el.getExt().toLowerCase()) || "rfa".equals(el.getExt().toLowerCase())){
							String[] json = el.getOutPath().split("beTile.json");
							ZipUtil.zip(json[0],json[0] + "tile-"+el.getFileVersionId()+".zip");
//							record.setFileHash(FileHash.md5HashCode(json[0] + "tile-"+el.getFileVersionId()+".zip"));
							readfile(json[0] + "tile-"+el.getFileVersionId()+".zip", dto, id,0,1);
						}else {
							readfile(el.getOutPath(), dto, id,0,0);
						}	
					}
					fileLevel = 0;
					readfile(el.getFilePath(), dto, id,1,0);
				}
			}
			record.setStatus(0);
			recordMapper.updateByPrimaryKeySelective(record);
		} catch (Exception e) {
			log.error(e.getMessage(), e);
		} finally {
			outer.remove(id);
		}
	}

	@Override
	public void addSynchroTask(List<String> fileId) {
		List<FileBasics> outerList = fileMapper.selectOuterFilesByIds(fileId);
//		if(null != outerList) {
		System.out.println("查询数据:"+JSONObject.toJSONString(outerList.get(0)));
			if (outerList.size() > 0) {
				outerList.stream().forEach(el -> {
					Example example = new Example(FileRecord.class);
					example.createCriteria().andEqualTo("fileId", el.getFileVersionId());
					int result = recordMapper.selectCountByExample(example);
					String id = null;
					if (result == 0) {
						fileExCount = 0;
						fileCount = 0;
						fileLevel = 0;
						FileRecord record = new FileRecord();
						id = UUIDUtil.getPK();
						record.setId(id);
						record.setStatus(-1);
						record.setFileStatus(0);
						record.setCreateDate(new Date());
						record.setFileId(el.getFileVersionId());
						record.setEnvirement(inner.getIdx());
						if("dwg".equals(el.getExt().toLowerCase())|| "dxf".equals(el.getExt().toLowerCase())) {
							try {
//								record.setFileHash(FileHash.md5HashCode(el.getFilePath()));
								readfileCount(el.getFilePath(), 1);
							} catch (Exception e) {
								e.printStackTrace();
							}
							record.setFileType(1);
						}else {
							if("0".equals(el.getStatus())) {
								try {
//									record.setFileHash(FileHash.md5HashCode(el.getFilePath()));
									readfileCount(el.getFilePath(), 1);
								} catch (Exception e) {
									e.printStackTrace();
								}
								record.setFileType(1);
							}else if("2".equals(el.getStatus())) {
								if(StringUtils.isNotBlank(el.getOutPath())) {
									try {
//										record.setFileHash(FileHash.md5HashCode(el.getOutPath()));
										readfileCount(el.getFilePath(), 0);
									} catch (Exception e) {
										e.printStackTrace();
									}
									record.setFileType(0);
								}else {
									try {
//										record.setFileHash(FileHash.md5HashCode(el.getFilePath()));
										readfileCount(el.getFilePath(), 1);
									} catch (Exception e) {
										e.printStackTrace();
									}
									record.setFileType(1);
								}
							}
						}
						record.setIndexExNum(fileExCount);
						record.setIndexNum(fileCount);
						recordMapper.insert(record);
						System.out.println("插入成功!");
					} 
				});
			}
//		}
		
	}

	@Override
	public void synchroTask() {
		int size = 5 - outer.size();
		if(size == 0) 
			return;
		
		List<FileRecord> fileRecords = contentMapper.getContentPage(outer.stream().collect(Collectors.toList()), 5);
		for (FileRecord fileRecord : fileRecords) {
			if(outer.contains(fileRecord.getId()))
				continue;
			outer.add(fileRecord.getId());
			executorService.execute(() -> {
				synchroInnerByFileId(fileRecord.getId());
				outer.remove(fileRecord.getId());
			});
		}
		
		
	}

接下来我将对以上代码进行讲解,此文章只是将我当时开发的思路讲出来,至于实现,每个人的需求都是不同的,可以根据需求做更改。
首先,正常的逻辑应该是,我们首先采用io流的方式,对文件的路径进行读取,获取到了byte[],然后按照单位进行切割,此处我是按照60M对文件进行切割,切割完毕存储到数据库中,为以后做合并文件之用。
我的程序开发思路是这样的,首先我这个程序目的是为了定时切割文件,但是又不能同时无限切割,因为这样会严重占用系统性能,所以设置一个线程集合,大小为5,每次最多读取5个文件,每次读取文件按照60M大小进行切割,如果小于等于60M,则保留源文件blob,进行存储。
重点注意,不要忘记,如果大于60M切割存储的时候不要忘记记录切割内容的顺序,方便合并,否则即使合并文件完成也无法打开。

public List<FileContent> readfile(String filepath, FilePathDTO basics, String id,Integer fileType,Integer isZip)
			throws FileNotFoundException, IOException {
		int eachSize = 60*1024*1024;
		List<FileContent> contentList = new ArrayList<>();
		try {
			File file = new File(filepath);
			if (!file.isDirectory()) {
				byte[] data = new byte[(int) file.length()];// 新建字节数组
				try {
					FileInputStream fis = new FileInputStream(file);
					fis.read(data);
					fis.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
				if (data.length > 0) {
					
					int fileNumber;// 计算被划分成多少份子文件
					if (file.length() % eachSize == 0) {
						fileNumber = (int) (data.length / eachSize);
					} else {
						fileNumber = (int) (data.length / eachSize) + 1;
					}
					if (fileNumber == 0) {
					//此处是我开发需求,可根据实际更改
						FileContent content = new FileContent();
						content.setId(UUIDUtil.getPK());
						content.setFileContent(data);
						content.setFileIndex(-1);
						content.setFileLevel(fileLevel);
						content.setFileId(basics.getFileVersionId());
						content.setFileType(fileType);
						content.setRecordId(id);
						content.setStatus("0");
						if(1 == isZip) {
							content.setZipPosition(filepath);
							String[] json = basics.getOutPath().split("beTile.json");
							content.setFilePosition(json[0]);
						}else {
							content.setFilePosition(file.getAbsolutePath());
						}
						content.setEnviroment(inner.getIdx());
						content.setIsZip(isZip);
						
						contentMapper.insertSelective(content);
						
					} else {
						for (int i = 0; i < fileNumber; i++) {

							byte[] eachContent = null;

							if (i != (fileNumber - 1)) {
								// 如果不是最后一个,每个长度相同
								eachContent = Arrays.copyOfRange(data, eachSize * i, eachSize * (i + 1));
							} else {
								// 最后一个(长度不一致)
								eachContent = Arrays.copyOfRange(data, eachSize * i, data.length);
							}
							FileContent content = new FileContent();
							content.setId(UUIDUtil.getPK());
							content.setFileContent(eachContent);
							content.setFileIndex(-1);
							content.setPointIndex(i);
							content.setFileLevel(fileLevel);
							content.setFileId(basics.getFileVersionId());
							content.setFileType(fileType);
							content.setRecordId(id);
							content.setIsZip(isZip);
							content.setStatus("0");
							if(1 == isZip) {
								content.setZipPosition(filepath);
								String[] json = basics.getOutPath().split("beTile.json");
								content.setFilePosition(json[0]);
							}else {
								content.setFilePosition(file.getAbsolutePath());
							}
							content.setEnviroment(inner.getIdx());
							contentMapper.insertSelective(content);	
							
						}		
					}	
				}
			} else if (file.isDirectory()) {
				File[] fileList2 = file.listFiles();
				List<File> fileList = new ArrayList<>();
				for (int i = 0; i < fileList2.length; i++) {
					if(!fileList2[i].isDirectory()) {
						fileList.add(fileList2[i]);
					}
				}
				for (int i = 0; i < fileList2.length; i++) {
					if(fileList2[i].isDirectory()) {
						fileList.add(fileList2[i]);
					}
				}
				fileLevel ++;
				for (int i = 0; i < fileList.size(); i++) {
					if (!fileList.get(i).isDirectory()) {
						byte[] data = new byte[(int) fileList.get(i).length()];// 新建字节数组
						try {
							FileInputStream fis = new FileInputStream(fileList.get(i));
							fis.read(data);
							fis.close();
						} catch (IOException e) {
							e.printStackTrace();
						}
						if (data.length > 0) {
							int fileNumber;// 计算被划分成多少份子文件
							if (file.length() % eachSize == 0) {
								fileNumber = (int) (data.length / eachSize);
							} else {
								fileNumber = (int) (data.length / eachSize) + 1;
							}
							if (fileNumber == 0) {
								FileContent content = new FileContent();
								content.setId(UUIDUtil.getPK());
								content.setFileContent(data);
								content.setFileIndex(i);
								content.setFileId(basics.getFileVersionId());
								content.setFileLevel(fileLevel);
								content.setFileType(fileType);
								content.setRecordId(id);
								content.setIsZip(isZip);
								content.setStatus("0");
								if(1 == isZip) {
									content.setZipPosition(filepath);
									String[] json = basics.getOutPath().split("beTile.json");
									content.setFilePosition(json[0]);
								}else {
									content.setFilePosition(file.getAbsolutePath());
								}
								content.setEnviroment(inner.getIdx());
								contentMapper.insertSelective(content);
							} else {
								for (int j = 0; j < fileNumber; j++) {

									byte[] eachContent = null;

									if (i != (fileNumber - 1)) {
										// 如果不是最后一个,每个长度相同
										eachContent = Arrays.copyOfRange(data, eachSize * i, eachSize * (i + 1));
									} else {
										// 最后一个(长度不一致)
										eachContent = Arrays.copyOfRange(data, eachSize * i, data.length);
									}
									FileContent content = new FileContent();
									content.setId(UUIDUtil.getPK());
									content.setFileContent(eachContent);
									content.setFileIndex(i);
									content.setPointIndex(j);
									content.setFileLevel(fileLevel);
									content.setFileId(basics.getFileVersionId());
									content.setFileType(fileType);
									content.setRecordId(id);
									content.setIsZip(isZip);
									content.setStatus("0");
									if(1 == isZip) {
										content.setZipPosition(filepath);
										String[] json = basics.getOutPath().split("beTile.json");
										content.setFilePosition(json[0]);
									}else {
										content.setFilePosition(file.getAbsolutePath());
									}
									content.setEnviroment(inner.getIdx());
									contentMapper.insertSelective(content);
								}
								
							}
							
						}

					} else if (fileList.get(i).isDirectory()) {
						fileLevel ++;
						readfile(fileList.get(i).getAbsolutePath(), basics, id,fileType,isZip);
					}
				}
			}
			
		} catch (FileNotFoundException e) {
			log.error(e.getMessage(), e);
		}
		return contentList;
	}

此处代码,为读取文件并切割的方法,之所以用到了迭代,是因为我这个接收的地址参数可能会出现是文件夹,而不是文件,所以就需要迭代读取地址,把里面的文件都读取出来。

总结

由于篇幅问题,合并我就不在这里说明,我将在我下一篇文章进行说明,当然,这个只是我粗略记录一下心得,以后会不断更新完善这篇文章。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值