package com.ard.tianyu.service.impl;
|
|
import com.ard.tianyu.component.minio.config.MinioConfig;
|
import com.ard.tianyu.component.minio.utils.MinioUtil;
|
import com.ard.tianyu.config.WaylinePlaningConfig;
|
import com.ard.tianyu.domain.dto.wayline.*;
|
import com.ard.tianyu.domain.entity.UavWayline;
|
import com.ard.tianyu.domain.enums.WaylineEnum;
|
import com.ard.tianyu.mapper.UavWaylineMapper;
|
import com.ard.tianyu.service.IGeoToolsService;
|
import com.ard.tianyu.service.IKmzFileService;
|
import com.ard.tianyu.util.Vertex;
|
import lombok.extern.slf4j.Slf4j;
|
import org.dom4j.*;
|
import org.dom4j.io.OutputFormat;
|
import org.dom4j.io.XMLWriter;
|
import org.springframework.scheduling.annotation.Async;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
import javax.annotation.Resource;
|
import java.io.*;
|
import java.time.LocalDateTime;
|
import java.time.ZoneOffset;
|
import java.util.List;
|
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipOutputStream;
|
|
/**
|
* @author liusuyi
|
* @version 3.0
|
* @date 2025/06/27
|
*/
|
@Service
|
@Slf4j
|
@Transactional
|
public class KmzFileServiceImpl implements IKmzFileService {
|
|
@Resource
|
private MinioConfig minioConfig;
|
|
@Resource
|
private IGeoToolsService geoToolsService;
|
|
@Resource
|
private WaylinePlaningConfig waylinePlaningConfig;
|
|
@Resource
|
private UavWaylineMapper uavWaylineMapper;
|
|
private Document initWayline(Boolean isTemplate) {
|
//创建Document对象
|
Document document = DocumentHelper.createDocument();
|
document.setXMLEncoding("UTF-8");
|
|
// 定义命名空间
|
String KML_NAMESPACE = "http://www.opengis.net/kml/2.2";
|
String WPML_NAMESPACE = "http://www.dji.com/wpmz/1.0.6";
|
|
//创建kml节点
|
QName kmlQName = QName.get("kml", Namespace.get("", KML_NAMESPACE));
|
Element kml = document.addElement(kmlQName);
|
//添加命名空间
|
kml.addNamespace("wpml", WPML_NAMESPACE);
|
//生成Document节点
|
Element wpml = kml.addElement("Document", KML_NAMESPACE);
|
//是否为模板
|
if (isTemplate) {
|
// Step 1: Implement File Creation Information
|
//wpml.addElement("wpml:author").addText(user);
|
wpml.addElement("wpml:createTime").addText(
|
String.valueOf(LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli()));
|
wpml.addElement("wpml:updateTime").addText(
|
String.valueOf(LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli()));
|
}
|
//返回
|
return document;
|
}
|
|
//产生kmz总体过程
|
private void gntTemplateKml(ArdWaylineDTO ardWaylineDTO, String savePath) {
|
//初始化文件头
|
Document reader = this.initWayline(true);
|
//Document元素
|
Element document = reader.getRootElement().element("Document");
|
//添加missionConfig信息
|
this.addMissionConfig(document, ardWaylineDTO);
|
//添加folder信息
|
Element folder = this.addFolder(document, ardWaylineDTO);
|
//2设置航点参数
|
List<ArdUavPositionDTO> uavPositions = ardWaylineDTO.getUavPositions();
|
//循环添加placemark
|
Integer actionGroupId = 0;
|
for (int i = 0; i < uavPositions.size(); i++) {
|
ArdUavPositionDTO onePosition = uavPositions.get(i);
|
this.addPlaceMark(folder, i, actionGroupId, onePosition);
|
if (onePosition.getActionGroup().size() > 0) {
|
actionGroupId += 1;
|
}
|
}
|
//打印输出结果
|
//log.info(reader.asXML());
|
//输出
|
String tmpKml = savePath + File.separator + "wpmz" + File.separator + "template.kml";
|
this.outputXml(tmpKml, reader);
|
}
|
|
public void gntWaylineWpml(ArdWaylineDTO ardWaylineDTO, String savePath) {
|
//初始化文件头
|
Document reader = this.initWayline(false);
|
//Document元素
|
Element document = reader.getRootElement().element("Document");
|
//添加missionConfig信息
|
this.addMissionConfig(document, ardWaylineDTO);
|
//添加folder信息
|
Element folder = this.addFolderWayline(document, ardWaylineDTO);
|
//2设置航点参数
|
//循环添加placemark
|
Integer actionGroupId = 0;
|
for (int i = 0; i < ardWaylineDTO.getUavPositions().size(); i++) {
|
ArdUavPositionDTO onePosition = ardWaylineDTO.getUavPositions().get(i);
|
this.addPlaceMarkWayline(folder, i, actionGroupId, onePosition, ardWaylineDTO);
|
if (onePosition.getActionGroup().size() > 0) {
|
actionGroupId += 1;
|
}
|
}
|
//打印输出结果
|
//log.info(reader.asXML());
|
//输出
|
String waylineWpml = savePath + File.separator + "wpmz" + File.separator + "waylines.wpml";
|
this.outputXml(waylineWpml, reader);
|
}
|
|
//missionConfig信息
|
private void addMissionConfig(Element document, ArdWaylineDTO ardWaylineDTO) {
|
//创建wpml:missionConfig元素
|
Element missionConfig = document.addElement("wpml:missionConfig");
|
//创建子元素
|
missionConfig.addElement("wpml:flyToWaylineMode").addText("safely");
|
missionConfig.addElement("wpml:finishAction").addText("goHome");
|
missionConfig.addElement("wpml:exitOnRCLost").addText("goContinue");
|
missionConfig.addElement("wpml:executeRCLostAction").addText("goBack");
|
missionConfig.addElement("wpml:takeOffSecurityHeight").addText("30");
|
//与第一个点重合
|
ArdPositionDTO firstPoint = ardWaylineDTO.getUavPositions().get(0).getUavPosition();
|
String refPoint = String.format("%s,%s,%s", firstPoint.getLatitude(), firstPoint.getLongitude()
|
, firstPoint.getAltitude());
|
missionConfig.addElement("wpml:takeOffRefPoint").addText(refPoint);
|
missionConfig.addElement("wpml:globalTransitionalSpeed").addText(String.valueOf(ardWaylineDTO.getGlobalFlySpeed()));
|
missionConfig.addElement("wpml:globalRTHHeight").addText(String.valueOf(ardWaylineDTO.getGlobalFlyHeight()));
|
//添加droneInfo
|
Element droneInfo = missionConfig.addElement("wpml:droneInfo");
|
droneInfo.addElement("wpml:droneEnumValue").addText("89");
|
droneInfo.addElement("wpml:droneSubEnumValue").addText("1");
|
//添加payloadInfo
|
Element payloadInfo = missionConfig.addElement("wpml:payloadInfo");
|
payloadInfo.addElement("wpml:payloadEnumValue").addText("43");
|
payloadInfo.addElement("wpml:payloadSubEnumValue").addText("0");
|
payloadInfo.addElement("wpml:payloadPositionIndex").addText("0");
|
}
|
|
//folder信息
|
private Element addFolder(Element document, ArdWaylineDTO ardWaylineDTO) {
|
//全局信息
|
Element folder = document.addElement("Folder");
|
folder.addElement("wpml:templateType").addText("waypoint");
|
folder.addElement("wpml:templateId").addText("0");
|
//坐标系统
|
Element waylineCoordinateSysParam = folder.addElement("wpml:waylineCoordinateSysParam");
|
waylineCoordinateSysParam.addElement("wpml:coordinateMode").addText("WGS84");
|
waylineCoordinateSysParam.addElement("wpml:heightMode").addText("relativeToStartPoint");
|
//
|
folder.addElement("wpml:autoFlightSpeed").addText(String.valueOf(ardWaylineDTO.getGlobalFlySpeed()));
|
folder.addElement("wpml:globalWaypointTurnMode").addText("toPointAndStopWithDiscontinuityCurvature");
|
folder.addElement("wpml:globalUseStraightLine").addText("1");
|
//全局航向角模式
|
Element globalWaypointHeadingParam = folder.addElement("wpml:globalWaypointHeadingParam");
|
globalWaypointHeadingParam.addElement("wpml:waypointHeadingMode").addText("followWayline");
|
globalWaypointHeadingParam.addElement("wpml:waypointHeadingYawPathMode").addText("followBadArc");
|
//
|
folder.addElement("wpml:gimbalPitchMode").addText("manual");//manual , usePointSetting
|
folder.addElement("wpml:globalHeight").addText(String.valueOf(ardWaylineDTO.getGlobalFlyHeight()));
|
//
|
return folder;
|
}
|
|
private Element addFolderWayline(Element document, ArdWaylineDTO ardWaylineDTO) {
|
//全局信息
|
Element folder = document.addElement("Folder");
|
folder.addElement("wpml:templateId").addText("0");
|
folder.addElement("wpml:executeHeightMode").addText("relativeToStartPoint");
|
folder.addElement("wpml:waylineId").addText("0");
|
folder.addElement("wpml:autoFlightSpeed").addText(String.valueOf(ardWaylineDTO.getGlobalFlySpeed()));
|
return folder;
|
}
|
|
//placemark信息
|
private void addPlaceMark(Element folder, Integer index, Integer actionGroupId, ArdUavPositionDTO onePostion) {
|
//添加placemark
|
Element placemark = folder.addElement("Placemark");
|
//转换坐标
|
//航点坐标位置转换
|
Double tLng = 0.0;
|
Double tLat = 0.0;
|
//转换坐标,将目标坐标转化为高德坐标
|
if (onePostion.getUavPosition().getLongitude() != null &&
|
onePostion.getUavPosition().getLatitude() != null) {
|
Vertex newVertex = geoToolsService.gcj02ToTargetCoordinate(
|
new Vertex(onePostion.getUavPosition().getLongitude(),
|
onePostion.getUavPosition().getLatitude()));
|
tLng = newVertex.x;
|
tLat = newVertex.y;
|
}
|
Element point = placemark.addElement("Point");
|
point.addElement("coordinates").addText(tLng + "," + tLat);
|
//添加一般元素
|
placemark.addElement("wpml:index").addText(String.valueOf(index));
|
placemark.addElement("wpml:ellipsoidHeight").addText(String.valueOf(onePostion.getUavPosition().getAltitude()));
|
placemark.addElement("wpml:height").addText(String.valueOf(onePostion.getUavPosition().getAltitude()));
|
//全局信息
|
placemark.addElement("wpml:useGlobalHeight").addText("1");
|
placemark.addElement("wpml:useGlobalSpeed").addText("1");
|
placemark.addElement("wpml:useGlobalHeadingParam").addText("1");
|
placemark.addElement("wpml:useGlobalTurnParam").addText("1");
|
placemark.addElement("wpml:useStraightLine").addText("1");
|
//添加actionGroup
|
if (onePostion.getActionGroup().size() > 0) {
|
Element actionGroup = placemark.addElement("wpml:actionGroup");
|
//添加动作组基础信息
|
actionGroup.addElement("wpml:actionGroupId").addText(String.valueOf(actionGroupId));
|
actionGroup.addElement("wpml:actionGroupStartIndex").addText(String.valueOf(index));
|
actionGroup.addElement("wpml:actionGroupEndIndex").addText(String.valueOf(index));
|
actionGroup.addElement("wpml:actionGroupMode").addText("sequence");
|
Element actionTrigger = actionGroup.addElement("wpml:actionTrigger");
|
actionTrigger.addElement("wpml:actionTriggerType").addText("reachPoint");
|
//定义action
|
Integer actionId = 0;
|
for (int j = 0; j < onePostion.getActionGroup().size(); j++) {
|
//逐个添加action
|
Integer actionCount = this.addAction(actionGroup, actionId, onePostion.getActionGroup().get(j));
|
actionId += actionCount;
|
}
|
}
|
}
|
|
//placemark信息
|
private void addPlaceMarkWayline(Element folder, Integer index, Integer actionGroupId,
|
ArdUavPositionDTO onePostion, ArdWaylineDTO ardWaylineDTO) {
|
//添加placemark
|
Element placemark = folder.addElement("Placemark");
|
//转换坐标
|
//航点坐标位置转换
|
Double tLng = 0.0;
|
Double tLat = 0.0;
|
//转换坐标,将目标坐标转化为高德坐标
|
if (onePostion.getUavPosition().getLongitude() != null &&
|
onePostion.getUavPosition().getLatitude() != null) {
|
Vertex newVertex = geoToolsService.gcj02ToTargetCoordinate(
|
new Vertex(onePostion.getUavPosition().getLongitude(),
|
onePostion.getUavPosition().getLatitude()));
|
tLng = newVertex.x;
|
tLat = newVertex.y;
|
}
|
Element point = placemark.addElement("Point");
|
point.addElement("coordinates").addText(tLng + "," + tLat);
|
//添加一般元素
|
placemark.addElement("wpml:index").addText(String.valueOf(index));
|
placemark.addElement("wpml:executeHeight").addText(String.valueOf(onePostion.getUavPosition().getAltitude()));
|
placemark.addElement("wpml:waypointSpeed").addText(String.valueOf(ardWaylineDTO.getGlobalFlySpeed()));
|
Element waypointHeadingParam = placemark.addElement("wpml:waypointHeadingParam");
|
waypointHeadingParam.addElement("wpml:waypointHeadingMode").addText("followWayline");
|
Element waypointTurnParam = placemark.addElement("wpml:waypointTurnParam");
|
waypointTurnParam.addElement("wpml:waypointTurnMode").addText(WaylineEnum.getDesc(onePostion.getFlightPathMode()));
|
waypointTurnParam.addElement("wpml:waypointTurnDampingDist").addText("0");
|
//添加actionGroup
|
if (onePostion.getActionGroup().size() > 0) {
|
Element actionGroup = placemark.addElement("wpml:actionGroup");
|
//添加动作组基础信息
|
actionGroup.addElement("wpml:actionGroupId").addText(String.valueOf(actionGroupId));
|
actionGroup.addElement("wpml:actionGroupStartIndex").addText(String.valueOf(index));
|
actionGroup.addElement("wpml:actionGroupEndIndex").addText(String.valueOf(index));
|
actionGroup.addElement("wpml:actionGroupMode").addText("sequence");
|
Element actionTrigger = actionGroup.addElement("wpml:actionTrigger");
|
actionTrigger.addElement("wpml:actionTriggerType").addText("reachPoint");
|
//定义action
|
Integer actionId = 0;
|
for (int j = 0; j < onePostion.getActionGroup().size(); j++) {
|
//逐个添加action
|
Integer actionCount = this.addAction(actionGroup, actionId, onePostion.getActionGroup().get(j));
|
actionId += actionCount;
|
}
|
}
|
}
|
//action
|
private Integer addAction(Element actionGroup, Integer index, ArdActionDTO actionDTO) {
|
Integer actionCount = 2;
|
//变焦动作
|
Element actionGimbal = actionGroup.addElement("wpml:action");
|
actionGimbal.addElement("wpml:actionId").addText(String.valueOf(index));
|
actionGimbal.addElement("wpml:actionActuatorFunc").addText("gimbalRotate");
|
Element param = actionGimbal.addElement("wpml:actionActuatorFuncParam");
|
param.addElement("wpml:payloadPositionIndex").addText(String.valueOf(0));
|
param.addElement("wpml:gimbalHeadingYawBase").addText("north");
|
param.addElement("wpml:gimbalRotateMode").addText("absoluteAngle");
|
param.addElement("wpml:gimbalPitchRotateEnable").addText(String.valueOf(1));
|
param.addElement("wpml:gimbalPitchRotateAngle").addText(String.valueOf(actionDTO.getActionGimbal().getPitch()));
|
param.addElement("wpml:gimbalRollRotateEnable").addText(String.valueOf(0));
|
param.addElement("wpml:gimbalRollRotateAngle").addText(String.valueOf(0));
|
param.addElement("wpml:gimbalYawRotateEnable").addText(String.valueOf(1));
|
param.addElement("wpml:gimbalYawRotateAngle").addText(String.valueOf(actionDTO.getActionGimbal().getYaw()));
|
param.addElement("wpml:gimbalRotateTimeEnable").addText(String.valueOf(0));
|
param.addElement("wpml:gimbalRotateTime").addText(String.valueOf(0));
|
//动作类型
|
switch (actionDTO.actionType) {
|
case 0://拍照
|
Element action0 = actionGroup.addElement("wpml:action");
|
action0.addElement("wpml:actionId").addText(String.valueOf(index + 1));
|
action0.addElement("wpml:actionActuatorFunc").addText("takePhoto");
|
Element param0 = action0.addElement("wpml:actionActuatorFuncParam");
|
param0.addElement("wpml:fileSuffix").addText("point");
|
param0.addElement("wpml:payloadPositionIndex").addText(String.valueOf(0));
|
break;
|
case 1://录像,拆解为3个动作
|
//添加开始录像动作
|
Element action11 = actionGroup.addElement("wpml:action");
|
action11.addElement("wpml:actionId").addText(String.valueOf(index + 1));
|
action11.addElement("wpml:actionActuatorFunc").addText("startRecord");
|
Element param11 = action11.addElement("wpml:actionActuatorFuncParam");
|
param11.addElement("wpml:fileSuffix").addText("point");
|
param11.addElement("wpml:payloadPositionIndex").addText(String.valueOf(0));
|
//添加新的悬停动作
|
Element action12 = actionGroup.addElement("wpml:action");
|
action12.addElement("wpml:actionId").addText(String.valueOf(index + 2));
|
action12.addElement("wpml:actionActuatorFunc").addText("hover");
|
Element param12 = action12.addElement("wpml:actionActuatorFuncParam");
|
param12.addElement("wpml:hoverTime").addText(String.valueOf(actionDTO.getActionParameter()));
|
//添加结束动作
|
Element action13 = actionGroup.addElement("wpml:action");
|
action13.addElement("wpml:actionId").addText(String.valueOf(index + 3));
|
action13.addElement("wpml:actionActuatorFunc").addText("stopRecord");
|
Element param13 = action13.addElement("wpml:actionActuatorFuncParam");
|
param13.addElement("wpml:payloadPositionIndex").addText(String.valueOf(0));
|
actionCount = 5;
|
break;
|
case 2://悬停 ,协议是3,前端发送为2
|
Element action2 = actionGroup.addElement("wpml:action");
|
action2.addElement("wpml:actionId").addText(String.valueOf(index + 1));
|
action2.addElement("wpml:actionActuatorFunc").addText("hover");
|
Element param2 = action2.addElement("wpml:actionActuatorFuncParam");
|
param2.addElement("wpml:hoverTime").addText(String.valueOf(actionDTO.getWaitTime()));
|
break;
|
default:
|
actionCount = 0;
|
log.info("未知的动作类型{}!", actionDTO.actionType);
|
break;
|
}
|
return actionCount;
|
}
|
|
//输出模板kml
|
private void outputXml(String vpath, Document doc) {
|
try {
|
OutputFormat format = OutputFormat.createPrettyPrint();
|
format.setEncoding("UTF-8"); //FileWriter改为FileOutputStream解决乱码问题
|
XMLWriter xmlWriter = new XMLWriter(new FileOutputStream(vpath), format);
|
xmlWriter.write(doc);
|
xmlWriter.close();
|
} catch (Exception e) {
|
log.error("输出航线文件失败:{}", vpath);
|
e.printStackTrace();
|
}
|
}
|
|
//创建路径
|
private String createSavePath(String waylineName) {
|
//创建航线名称路径
|
String pathStr = waylinePlaningConfig.getWaylineSavePath() + File.separator + waylineName;
|
File savePath = new File(pathStr);
|
if (!savePath.exists()) {
|
savePath.mkdirs();
|
} else {
|
deleteFile(savePath);
|
savePath.mkdirs();
|
}
|
//创建wpmz
|
File wpmz = new File(pathStr + File.separator + "wpmz");
|
wpmz.mkdir();
|
//创建res
|
File res = new File(pathStr + File.separator + "wpmz" + File.separator + "res");
|
res.mkdir();
|
return pathStr;
|
}
|
|
private void deleteFile(File filePath) {
|
//判断路径是否存在
|
if (filePath.exists()) {
|
//判断是否是目录
|
if (filePath.isDirectory()) {
|
//将目录逐层拆分成数组元素
|
File[] files = filePath.listFiles();
|
for (File f : files) {
|
//递归调用,由最底层往上逐层删除
|
deleteFile(f);
|
}
|
}
|
//如果是文件,直接删除
|
filePath.delete();
|
}
|
}
|
|
//输出MKZ过程
|
@Override
|
@Async
|
public void outputKmz(ArdWaylineDTO ardWaylineDTO) {
|
try {
|
//创建目录
|
String savePath = this.createSavePath(ardWaylineDTO.getWaylineName());
|
//输出模板kml
|
this.gntTemplateKml(ardWaylineDTO, savePath);
|
//输出航线wpml
|
this.gntWaylineWpml(ardWaylineDTO, savePath);
|
//压缩输出成kmz
|
String fileName = ardWaylineDTO.getWaylineName() + ".kmz";
|
String kmzPath = waylinePlaningConfig.getWaylineSavePath() + File.separator + fileName;
|
//输出kmz文件,是否成功
|
Boolean isSuccess = this.toKmz(kmzPath, savePath + File.separator + "wpmz",
|
true);
|
if (isSuccess) {
|
//上传kmz文件到对象数据库
|
InputStream inputStream = new FileInputStream(kmzPath);
|
//构建记录
|
String objectKey = fileName;
|
//若已经存在,则先删除,再添加
|
if (MinioUtil.exists(minioConfig.getBucketName(), objectKey))
|
MinioUtil.delete(minioConfig.getBucketName(), objectKey);
|
String kmzUrl = MinioUtil.uploadInputStream(minioConfig.getBucketName(), objectKey, inputStream,
|
inputStream.available(), "application/octet-stream");
|
// 更新航线kmz地址
|
UavWayline uavWayline = UavWayline.builder()
|
.id(ardWaylineDTO.waylineId)
|
.kmzUrl(kmzUrl)
|
.build();
|
uavWaylineMapper.updateUavWayline(uavWayline);
|
}
|
} catch (Exception e) {
|
e.printStackTrace();
|
log.info("生成kmz文件失败!");
|
}
|
}
|
|
private Boolean toKmz(String zipFileName, String sourceFileName, boolean KeepDirStructure) {
|
Boolean result = true;
|
long start = System.currentTimeMillis();//开始
|
ZipOutputStream zos = null;
|
try {
|
FileOutputStream fileOutputStream = new FileOutputStream(zipFileName);
|
zos = new ZipOutputStream(fileOutputStream);
|
File sourceFile = new File(sourceFileName);
|
compress(sourceFile, zos, sourceFile.getName(), KeepDirStructure);
|
long end = System.currentTimeMillis();//结束
|
System.out.println("压缩完成,耗时:" + (end - start) + " 毫秒");
|
} catch (Exception e) {
|
result = false;
|
e.printStackTrace();
|
} finally {
|
if (zos != null) {
|
try {
|
zos.close();
|
} catch (IOException e) {
|
e.getStackTrace();
|
}
|
}
|
}
|
return result;
|
}
|
|
private void compress(File sourceFile, ZipOutputStream zos, String name,
|
boolean KeepDirStructure) throws Exception {
|
byte[] buf = new byte[2 * 1024];
|
if (sourceFile.isFile()) {
|
// 向zip输出流中添加一个zip实体,构造器中name为zip实体的文件的名字
|
zos.putNextEntry(new ZipEntry(name));
|
// copy文件到zip输出流中
|
int len;
|
FileInputStream in = new FileInputStream(sourceFile);
|
while ((len = in.read(buf)) != -1) {
|
zos.write(buf, 0, len);
|
}
|
// Complete the entry
|
zos.closeEntry();
|
in.close();
|
} else {
|
File[] listFiles = sourceFile.listFiles();
|
if (listFiles == null || listFiles.length == 0) {
|
// 需要保留原来的文件结构时,需要对空文件夹进行处理
|
if (KeepDirStructure) {
|
// 空文件夹的处理
|
zos.putNextEntry(new ZipEntry(name + "/"));
|
// 没有文件,不需要文件的copy
|
zos.closeEntry();
|
}
|
} else {
|
for (File file : listFiles) {
|
// 判断是否需要保留原来的文件结构
|
if (KeepDirStructure) {
|
// 注意:file.getName()前面需要带上父文件夹的名字加一斜杠,
|
// 不然最后压缩包中就不能保留原来的文件结构,即:所有文件都跑到压缩包根目录下了
|
compress(file, zos, name + "/" + file.getName(), KeepDirStructure);
|
} else {
|
compress(file, zos, file.getName(), KeepDirStructure);
|
}
|
|
}
|
}
|
}
|
}
|
|
}
|