关于Java处理Excel常规列表记录,并入库的操作
1.描述
对于常规的Excel列表(二维表格)的入库处理,一般的mysql连接工具,例如Navicat就支持。但是,因为业务需要,不想每次都去手动导入,所以这里采用编码且定时任务的形式来实现。
2.Excel常规列表处理
2.1 常规的二维表格示例

2.2 编码
2.2.1 实体
package com.chinaunicom.medical.business.cdm.dao.cdm.entity;import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;import java.time.LocalDateTime;/*** @Description * @Author ZhaoShuhao* @Date: 2024-11-01 09:58:18*/@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@Schema(name=" ods_resident_record_excel_data ", description=" 原始居民建档记录Excel表 ")
@TableName(value = "ods_resident_record_excel_data",autoResultMap = true)
public class OdsResidentRecordExcelData {@Schema(name="id",description="主键id")private Long id;@Schema(name="myNumber",description="个人编号-档案编号")private String myNumber;@Schema(name="responsibleDoctor",description="*责任医生:")private String responsibleDoctor;@Schema(name="archiveModifier",description="档案修改人")private String archiveModifier;@Schema(name="hypertension",description="高血压")private String hypertension;@Schema(name="oldPeople",description="老年人")private String oldPeople;@Schema(name="coronaryHeartDisease",description="冠心病")private String coronaryHeartDisease;@Schema(name="signTime",description="签约日期:")private String signTime;@Schema(name="diabetes",description="糖尿病")private String diabetes;@Schema(name="stroke",description="脑卒中")private String stroke;@Schema(name="disabledPerson",description="残疾人")private String disabledPerson;@Schema(name="tumor",description="肿瘤")private String tumor;@Schema(name="idCard",description="身份证号")private String idCard;@Schema(name="internalFileNumber",description="内部档案号")private String internalFileNumber;@Schema(name="name",description="姓名")private String name;@Schema(name="otherName",description="联系人姓名")private String otherName;@Schema(name="gender",description="性别")private String gender;@Schema(name="permanentAddressDetail",description="*户籍详细地址:")private String permanentAddressDetail;@Schema(name="residentialAddressStreet",description="居住地址街道")private String residentialAddressStreet;@Schema(name="residentialAddressDetail",description="居住地址详细")private String residentialAddressDetail;@Schema(name="birthday",description="出生日期")private String birthday;@Schema(name="filingDoctor",description="*建档医生:")private String filingDoctor;@Schema(name="filingTime",description="*建档日期:")private String filingTime;@Schema(name="otherPhone",description="联系人电话")private String otherPhone;@Schema(name="residentialAddressVillage",description="居住地址村")private String residentialAddressVillage;@Schema(name="mentalDisease",description="精神病")private String mentalDisease;@Schema(name="myPhone",description="本人电话")private String myPhone;@Schema(name="inputTime",description="入选日期:")private String inputTime;@Schema(name="healthcareWorker",description="是否家庭保健员:")private String healthcareWorker;@Schema(name="manageInfo",description="管理情况")private String manageInfo;@Schema(name="status",description="状态")private long status;@Schema(name="extend",description="扩展字段")private String extend;@Schema(name="create_time",description="创建时间")private LocalDateTime createTime;@Schema(name="syncStatus",description="同步状态")private Integer syncStatus;
}
2.2.2 mapper
package com.chinaunicom.medical.business.cdm.dao.cdm.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.chinaunicom.medical.business.cdm.dao.cdm.entity.OdsResidentRecordExcelData;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;import java.time.LocalDateTime;
import java.util.Collection;/*** @author ZhaoShuhao* @description 针对表【ods_resident_record_excel_data(原始居民建档记录Excel表)】的数据库操作Mapper* @createDate 2024-11-01 09:58:59* @Entity mybatisxTest.model.OdsResidentRecordExcelData*/
@Mapper
public interface OdsResidentRecordExcelDataMapper extends BaseMapper<OdsResidentRecordExcelData> {@Select("select min(create_time) from ods_resident_record_excel_data where sync_status = 0")LocalDateTime getMinUnSyncDataTime();@Select({"<script>","update ods_resident_record_excel_data set sync_status = sync_status + 1","where id in","<foreach collection='patientIds' item='patient_id' open='(' separator=',' close=')'>","#{patient_id}","</foreach>","</script>"})void batchSetSynced(@Param("patientIds") Collection<Long> patientIds);}
2.2.3 业务类
package com.chinaunicom.medical.business.cdm.analysis.excel.residentrecord;import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chinaunicom.medical.business.cdm.dao.cdm.entity.OdsResidentRecordExcelData;
import com.chinaunicom.medical.business.cdm.dao.cdm.mapper.OdsResidentRecordExcelDataMapper;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;/*** 居民健康档案(建档记录)列表记录,Excel解析*/
@Service
@Slf4j
public class OdsResidentRecordExcelDataAnalysis extends ServiceImpl<OdsResidentRecordExcelDataMapper, OdsResidentRecordExcelData> {private final AtomicInteger threadTaskCount = new AtomicInteger(0);private final ThreadPoolExecutor executor = new ThreadPoolExecutor(20,20,5, TimeUnit.SECONDS,new LinkedBlockingDeque<>());private final List<OdsResidentRecordExcelData> dataList = new CopyOnWriteArrayList<>();private final List<String> successFileList = Collections.synchronizedList(new ArrayList<>());private final List<String> failFileList = Collections.synchronizedList(new ArrayList<>());/*** C:\Users\KeepHappy\Desktop\清华长庚-慢病-数据采集\数据采集列表-与详情关联\居民建档记录列表*/@SneakyThrowspublic void analysis(String fileAnalysisDirPath,String successFileDirPath,String failFileDirPath) {String fileDirPath = StrUtil.removeSuffix(fileAnalysisDirPath, File.separator);if(!FileUtil.exist(fileDirPath)){log.info("{}文件夹不存在,退出解析",fileDirPath);return;}List<String> fileNameList = FileUtil.listFileNames(fileDirPath);if(CollUtil.isNotEmpty(fileNameList)){new ArrayList<>(fileNameList).stream().forEach(baseInfoFileName ->{//解析 基本信息executor.execute(()->analysisBaseInfoExcel(fileDirPath+File.separator+baseInfoFileName));});CountDownLatch countDownLatch = new CountDownLatch(1);new Thread(()->{try {ThreadUtil.sleep(3000);while (threadTaskCount.get()>0){ThreadUtil.sleep(1000);}executor.shutdownNow();log.info("解析成功{}", JSONUtil.toJsonStr(dataList));if(CollUtil.isNotEmpty(dataList)){saveBatch(dataList);}//解析后,移动文件String successFilePath = StrUtil.removeSuffix(successFileDirPath, File.separator);String failFilePath = StrUtil.removeSuffix(failFileDirPath, File.separator);//移动文件FileUtil.mkdir(successFilePath);FileUtil.mkdir(failFilePath);successFileList.forEach(filePath ->{String fileName = FileUtil.getName(filePath);FileUtil.move(new File(filePath),new File(successFileDirPath+File.separator+fileName),true);});failFileList.forEach(filePath ->{String fileName = FileUtil.getName(filePath);FileUtil.move(new File(filePath),new File(failFileDirPath+File.separator+fileName),true);});} catch (Throwable e) {log.error("发生异常",e);}countDownLatch.countDown();}).start();countDownLatch.await();}}/*** 解析基本信息*/private void analysisBaseInfoExcel(String filePath){if(!FileUtil.exist(filePath)){log.info("文件不存在=>{}",filePath);return;}boolean success =false;ExcelReader reader = null;try {threadTaskCount.incrementAndGet();reader = ExcelUtil.getReader(FileUtil.getInputStream(filePath),true);List<List<Object>> excelDataList = reader.read(1);for (List<Object> data : excelDataList) {OdsResidentRecordExcelData odsResidentRecordExcelData = new OdsResidentRecordExcelData();odsResidentRecordExcelData.setFilingDoctor(StrUtil.replace(StrUtil.toString(CollUtil.get(data,0)),"null",""));odsResidentRecordExcelData.setFilingTime(StrUtil.replace(StrUtil.toString(CollUtil.get(data,1)),"null",""));odsResidentRecordExcelData.setName(StrUtil.replace(StrUtil.toString(CollUtil.get(data,2)),"null",""));odsResidentRecordExcelData.setMyPhone(StrUtil.replace(StrUtil.toString(CollUtil.get(data,3)),"null",""));odsResidentRecordExcelData.setCoronaryHeartDisease(StrUtil.replace(StrUtil.toString(CollUtil.get(data,4)),"null",""));odsResidentRecordExcelData.setHypertension(StrUtil.replace(StrUtil.toString(CollUtil.get(data,5)),"null",""));odsResidentRecordExcelData.setDiabetes(StrUtil.replace(StrUtil.toString(CollUtil.get(data,6)),"null",""));odsResidentRecordExcelData.setStroke(StrUtil.replace(StrUtil.toString(CollUtil.get(data,7)),"null",""));odsResidentRecordExcelData.setTumor(StrUtil.replace(StrUtil.toString(CollUtil.get(data,8)),"null",""));odsResidentRecordExcelData.setArchiveModifier(StrUtil.replace(StrUtil.toString(CollUtil.get(data,9)),"null",""));odsResidentRecordExcelData.setSignTime(StrUtil.replace(StrUtil.toString(CollUtil.get(data,10)),"null",""));odsResidentRecordExcelData.setResidentialAddressDetail(StrUtil.replace(StrUtil.toString(CollUtil.get(data,11)),"null",""));odsResidentRecordExcelData.setBirthday(StrUtil.replace(StrUtil.toString(CollUtil.get(data,12)),"null",""));odsResidentRecordExcelData.setPermanentAddressDetail(StrUtil.replace(StrUtil.toString(CollUtil.get(data,13)),"null",""));odsResidentRecordExcelData.setResidentialAddressStreet(StrUtil.replace(StrUtil.toString(CollUtil.get(data,14)),"null",""));odsResidentRecordExcelData.setResidentialAddressVillage(StrUtil.replace(StrUtil.toString(CollUtil.get(data,15)),"null",""));odsResidentRecordExcelData.setOtherPhone(StrUtil.replace(StrUtil.toString(CollUtil.get(data,16)),"null",""));odsResidentRecordExcelData.setOtherName(StrUtil.replace(StrUtil.toString(CollUtil.get(data,17)),"null",""));odsResidentRecordExcelData.setIdCard(StrUtil.replace(StrUtil.toString(CollUtil.get(data,18)),"null",""));odsResidentRecordExcelData.setGender(StrUtil.replace(StrUtil.toString(CollUtil.get(data,19)),"null",""));odsResidentRecordExcelData.setHealthcareWorker(StrUtil.replace(StrUtil.toString(CollUtil.get(data,20)),"null",""));odsResidentRecordExcelData.setMyNumber(StrUtil.replace(StrUtil.toString(CollUtil.get(data,21)),"null",""));odsResidentRecordExcelData.setDisabledPerson(StrUtil.replace(StrUtil.toString(CollUtil.get(data,22)),"null",""));odsResidentRecordExcelData.setResponsibleDoctor(StrUtil.replace(StrUtil.toString(CollUtil.get(data,23)),"null",""));odsResidentRecordExcelData.setOldPeople(StrUtil.replace(StrUtil.toString(CollUtil.get(data,24)),"null",""));odsResidentRecordExcelData.setMentalDisease(StrUtil.replace(StrUtil.toString(CollUtil.get(data,25)),"null",""));odsResidentRecordExcelData.setInputTime(StrUtil.replace(StrUtil.toString(CollUtil.get(data,26)),"null",""));odsResidentRecordExcelData.setManageInfo(StrUtil.replace(StrUtil.toString(CollUtil.get(data,27)),"null",""));odsResidentRecordExcelData.setInternalFileNumber(StrUtil.replace(StrUtil.toString(CollUtil.get(data,28)),"null",""));odsResidentRecordExcelData.setSyncStatus(0);dataList.add(odsResidentRecordExcelData);}success = true;} catch (Exception e) {log.error("解析基本信息异常,当前文件{}",filePath,e);}finally {threadTaskCount.decrementAndGet();IoUtil.close(reader);List<String> destList = success ? successFileList : failFileList;destList.add(filePath);}}
}
2.2.4 定时任务
package com.chinaunicom.medical.business.cdm.schedule;import com.alibaba.nacos.common.executor.ExecutorFactory;
import com.chinaunicom.medical.business.cdm.analysis.excel.diabetes.OdsDiabetesFileInfoAnalysis;
import com.chinaunicom.medical.business.cdm.analysis.excel.diabetes.OdsDiabetesFileRecordsAnalysis;
import com.chinaunicom.medical.business.cdm.analysis.excel.diabetes.OdsDiabetesFollowAnalysis;
import com.chinaunicom.medical.business.cdm.analysis.excel.diabetes.OdsDiabetesFollowRecordsAnalysis;
import com.chinaunicom.medical.business.cdm.analysis.excel.hypertension.OdsHypertensionArchiveDetailExcelDataAnalysis;
import com.chinaunicom.medical.business.cdm.analysis.excel.hypertension.OdsHypertensionArchiveExcelDataAnalysis;
import com.chinaunicom.medical.business.cdm.analysis.excel.hypertension.OdsHypertensionFollowDetailExcelDataAnalysis;
import com.chinaunicom.medical.business.cdm.analysis.excel.hypertension.OdsHypertensionFollowExcelDataAnalysis;
import com.chinaunicom.medical.business.cdm.analysis.excel.medicalexamination.OdsMedicalExaminationDetailExcelAnalysis;
import com.chinaunicom.medical.business.cdm.analysis.excel.residentrecord.OdsResidentRecordDetailExcelAnalysis;
import com.chinaunicom.medical.business.cdm.analysis.excel.residentrecord.OdsResidentRecordExcelDataAnalysis;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;import javax.annotation.Resource;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;@Component
public class ExcelDataScheduler {//居民健康档案(建档)列表记录@Value("${ods.resident.record.source:数据采集列表-与详情关联/居民建档记录列表}")private String odsResidentRecordSourcePath;@Value("${ods.resident.record.success:数据采集列表-与详情关联/居民建档记录列表/success}")private String odsResidentRecordSuccessPath;@Value("${ods.resident.record.fail:数据采集列表-与详情关联/居民建档记录列表/fail}")private String odsResidentRecordFailPath;@Resourceprivate OdsResidentRecordExcelDataAnalysis odsResidentRecordExcelDataAnalysis;private final ExecutorService executorService = ExecutorFactory.newFixedExecutorService(1);@Scheduled(cron = "0 0/30 * * * ?")public void load() {//添加异步任务记得调整executorService的构造参数executorService.submit(() -> odsResidentRecordExcelDataAnalysis.analysis(odsResidentRecordSourcePath,odsResidentRecordSuccessPath,odsResidentRecordFailPath));}
}
2.3 代码解析
2.3.1主要成员变量
threadTaskCount:AtomicInteger,用于记录当前正在处理的任务数
private final AtomicInteger threadTaskCount = new AtomicInteger(0);
executor:ThreadPoolExecutor,用于并发处理文件解析任务
private final ThreadPoolExecutor executor = new ThreadPoolExecutor(20, 20, 5, TimeUnit.SECONDS, new LinkedBlockingDeque<>());
dataList:CopyOnWriteArrayList,用于存储解析后的数据对象
private final List<OdsResidentRecordExcelData> dataList = new CopyOnWriteArrayList<>();
successFileList 和 failFileList:synchronizedList,用于存储成功和失败的文件路径。
private final List<String> successFileList = Collections.synchronizedList(new ArrayList<>());
private final List<String> failFileList = Collections.synchronizedList(new ArrayList<>());
2.3.2 主要方法
(1)analysis
- 方法签名:
public void analysis(String fileAnalysisDirPath, String successFileDirPath, String failFileDirPath) - 参数:
fileAnalysisDirPath:需要解析的Excel文件所在目录。successFileDirPath:解析成功后文件的存放目录。failFileDirPath:解析失败后文件的存放目录。
检查文件夹存在:检查指定的文件夹是否存在,如果不存在则记录日志并退出解析。
String fileDirPath = StrUtil.removeSuffix(fileAnalysisDirPath, File.separator);
if (!FileUtil.exist(fileDirPath)) {log.info("{}文件夹不存在,退出解析", fileDirPath);return;
}
列出文件名:获取指定目录下的所有文件名。
List<String> fileNameList = FileUtil.listFileNames(fileDirPath);
并发解析基本信息:对每个文件创建一个解析任务,使用线程池并发执行。
if (CollUtil.isNotEmpty(fileNameList)) {new ArrayList<>(fileNameList).stream().forEach(baseInfoFileName -> {executor.execute(() -> analysisBaseInfoExcel(fileDirPath + File.separator + baseInfoFileName));});
}
等待任务完成:使用CountDownLatch等待所有解析任务完成,然后关闭线程池。
CountDownLatch countDownLatch = new CountDownLatch(1);
new Thread(() -> {try {ThreadUtil.sleep(3000);while (threadTaskCount.get() > 0) {ThreadUtil.sleep(1000);}executor.shutdownNow();log.info("解析成功{}", JSONUtil.toJsonStr(dataList));if (CollUtil.isNotEmpty(dataList)) {saveBatch(dataList);}// 移动文件String successFilePath = StrUtil.removeSuffix(successFileDirPath, File.separator);String failFilePath = StrUtil.removeSuffix(failFileDirPath, File.separator);FileUtil.mkdir(successFilePath);FileUtil.mkdir(failFilePath);successFileList.forEach(filePath -> {String fileName = FileUtil.getName(filePath);FileUtil.move(new File(filePath), new File(successFilePath + File.separator + fileName), true);});failFileList.forEach(filePath -> {String fileName = FileUtil.getName(filePath);FileUtil.move(new File(filePath), new File(failFilePath + File.separator + fileName), true);});} catch (Throwable e) {log.error("发生异常", e);} finally {countDownLatch.countDown();}
}).start();
countDownLatch.await();
(2)analysisBaseInfoExcel
方法签名:
private void analysisBaseInfoExcel(String filePath)
参数:
filePath:需要解析的Excel文件路径。
功能:
检查文件存在:检查文件是否存在,如果不存在则记录日志并返回。
if (!FileUtil.exist(filePath)) {log.info("文件不存在=>{}", filePath);return;
}
读取Excel文件:使用ExcelUtil读取Excel文件,解析基本信息并填充到OdsResidentRecordExcelData对象中。
boolean success = false;
ExcelReader reader = null;
try {threadTaskCount.incrementAndGet();reader = ExcelUtil.getReader(FileUtil.getInputStream(filePath), true);List<List<Object>> excelDataList = reader.read(1);for (List<Object> data : excelDataList) {OdsResidentRecordExcelData odsResidentRecordExcelData = new OdsResidentRecordExcelData();odsResidentRecordExcelData.setFilingDoctor(StrUtil.replace(StrUtil.toString(CollUtil.get(data, 0)), "null", ""));odsResidentRecordExcelData.setFilingTime(StrUtil.replace(StrUtil.toString(CollUtil.get(data, 1)), "null", ""));odsResidentRecordExcelData.setName(StrUtil.replace(StrUtil.toString(CollUtil.get(data, 2)), "null", ""));odsResidentRecordExcelData.setMyPhone(StrUtil.replace(StrUtil.toString(CollUtil.get(data, 3)), "null", ""));odsResidentRecordExcelData.setCoronaryHeartDisease(StrUtil.replace(StrUtil.toString(CollUtil.get(data, 4)), "null", ""));odsResidentRecordExcelData.setHypertension(StrUtil.replace(StrUtil.toString(CollUtil.get(data, 5)), "null", ""));odsResidentRecordExcelData.setDiabetes(StrUtil.replace(StrUtil.toString(CollUtil.get(data, 6)), "null", ""));odsResidentRecordExcelData.setStroke(StrUtil.replace(StrUtil.toString(CollUtil.get(data, 7)), "null", ""));odsResidentRecordExcelData.setTumor(StrUtil.replace(StrUtil.toString(CollUtil.get(data, 8)), "null", ""));odsResidentRecordExcelData.setArchiveModifier(StrUtil.replace(StrUtil.toString(CollUtil.get(data, 9)), "null", ""));odsResidentRecordExcelData.setSignTime(StrUtil.replace(StrUtil.toString(CollUtil.get(data, 10)), "null", ""));odsResidentRecordExcelData.setResidentialAddressDetail(StrUtil.replace(StrUtil.toString(CollUtil.get(data, 11)), "null", ""));odsResidentRecordExcelData.setBirthday(StrUtil.replace(StrUtil.toString(CollUtil.get(data, 12)), "null", ""));odsResidentRecordExcelData.setPermanentAddressDetail(StrUtil.replace(StrUtil.toString(CollUtil.get(data, 13)), "null", ""));odsResidentRecordExcelData.setResidentialAddressStreet(StrUtil.replace(StrUtil.toString(CollUtil.get(data, 14)), "null", ""));odsResidentRecordExcelData.setResidentialAddressVillage(StrUtil.replace(StrUtil.toString(CollUtil.get(data, 15)), "null", ""));odsResidentRecordExcelData.setOtherPhone(StrUtil.replace(StrUtil.toString(CollUtil.get(data, 16)), "null", ""));odsResidentRecordExcelData.setOtherName(StrUtil.replace(StrUtil.toString(CollUtil.get(data, 17)), "null", ""));odsResidentRecordExcelData.setIdCard(StrUtil.replace(StrUtil.toString(CollUtil.get(data, 18)), "null", ""));odsResidentRecordExcelData.setGender(StrUtil.replace(StrUtil.toString(CollUtil.get(data, 19)), "null", ""));odsResidentRecordExcelData.setHealthcareWorker(StrUtil.replace(StrUtil.toString(CollUtil.get(data, 20)), "null", ""));odsResidentRecordExcelData.setMyNumber(StrUtil.replace(StrUtil.toString(CollUtil.get(data, 21)), "null", ""));odsResidentRecordExcelData.setDisabledPerson(StrUtil.replace(StrUtil.toString(CollUtil.get(data, 22)), "null", ""));odsResidentRecordExcelData.setResponsibleDoctor(StrUtil.replace(StrUtil.toString(CollUtil.get(data, 23)), "null", ""));odsResidentRecordExcelData.setOldPeople(StrUtil.replace(StrUtil.toString(CollUtil.get(data, 24)), "null", ""));odsResidentRecordExcelData.setMentalDisease(StrUtil.replace(StrUtil.toString(CollUtil.get(data, 25)), "null", ""));odsResidentRecordExcelData.setInputTime(StrUtil.replace(StrUtil.toString(CollUtil.get(data, 26)), "null", ""));odsResidentRecordExcelData.setManageInfo(StrUtil.replace(StrUtil.toString(CollUtil.get(data, 27)), "null", ""));odsResidentRecordExcelData.setInternalFileNumber(StrUtil.replace(StrUtil.toString(CollUtil.get(data, 28)), "null", ""));odsResidentRecordExcelData.setSyncStatus(0);dataList.add(odsResidentRecordExcelData);}success = true;
} catch (Exception e) {log.error("解析基本信息异常,当前文件{}", filePath, e);
} finally {threadTaskCount.decrementAndGet();IoUtil.close(reader);List<String> destList = success ? successFileList : failFileList;destList.add(filePath);
}
2.3.3 多线程处理
- 线程池:使用
ThreadPoolExecutor创建固定大小的线程池,确保并发解析文件时不会消耗过多资源。private final ThreadPoolExecutor executor = new ThreadPoolExecutor(20, 20, 5, TimeUnit.SECONDS, new LinkedBlockingDeque<>()); - 计数器:使用
AtomicInteger记录正在处理的任务数,确保所有任务完成后才进行后续操作。private final AtomicInteger threadTaskCount = new AtomicInteger(0); - 同步列表:使用
Collections.synchronizedList创建线程安全的列表,用于存储成功和失败的文件路径。private final List<String> successFileList = Collections.synchronizedList(new ArrayList<>()); private final List<String> failFileList = Collections.synchronizedList(new ArrayList<>());
2.3.4 文件管理
- 文件移动:解析完成后,根据解析结果将文件移动到不同的目录,便于后续管理和审计。
FileUtil.move(new File(filePath), new File(successFilePath + File.separator + fileName), true); FileUtil.move(new File(filePath), new File(failFilePath + File.separator + fileName), true);
相关文章:
关于Java处理Excel常规列表记录,并入库的操作
1.描述 对于常规的Excel列表(二维表格)的入库处理,一般的mysql连接工具,例如Navicat就支持。但是,因为业务需要,不想每次都去手动导入,所以这里采用编码且定时任务的形式来实现。 2.Excel常规列…...
深入理解 JavaScript 中的 Array.find() 方法:原理、性能优势与实用案例详解
目录 深入理解 JavaScript 中的 Array.find() 方法:原理、性能优势与实用案例详解 一、引言:为什么要使用Array.find() 二、Array.find()的使用与技巧 1、基础语法 2、返回值 3、使用技巧 三、Array.find()的优势与实际应用案例 1、利用返回引用…...
计算机网络安全 —— 对称加密算法 DES (一)
一、对称加密算法概念# 我们通过计算机网络传输数据时,如果无法防止他人窃听, 可以利用密码学技术将发送的数据变换成对任何不知道如何做逆变换的人都不可理解的形式, 从而保证了数据的机密性。这种变换被称为加密( encryptio…...
5. ARM_指令集
概述 分类 汇编中的符号: 指令:能够编译生成一条32位机器码,并且能被处理器识别和执行伪指令:本身不是指令,编译器可以将其替换成若干条指令伪操作:不会生成指令,只是在编译阶段告诉编译器怎…...
Jenkins的pipeline Script的 每个组件的详细讲解
在Jenkins的Pipeline脚本中,各个组件的配置和Groovy的一些常用函数起到了决定性的作用,帮助开发人员控制自动化流程的执行。以下是对Jenkins Pipeline的主要组件和Groovy常用函数的详细讲解: 1. Jenkins Pipeline主要组件 1.1 agent 功能&…...
Tomcat 和 Netty 的区别及应用场景分析
在 Java Web 开发中,Tomcat 和 Netty 都是常见的网络框架,它们各自有着不同的设计理念和适用场景。本文将通过详细的对比和实际场景示例,帮助你理解 Tomcat 和 Netty 在功能、性能、架构等方面的差异,帮助你在实际开发中做出更合理…...
6.C操作符详解,深入探索操作符与字符串处理
C操作符详解,深入探索操作符与字符串处理 C语言往期系列文章目录 往期回顾: C语言是什么?编程界的‘常青树’,它的辉煌你不可不知VS 2022 社区版C语言的安装教程,不要再卡在下载0B/s啦C语言入门:解锁基础…...
生数科技发布 Vidu 1.5 新版本,引领视频大模型新潮流
在国内视频大模型领域,生数科技一直以创新和突破而备受瞩目。近日,生数科技再度发力,发布了 Vidu 1.5 新版本,为视频创作带来了全新的变革与机遇。 Vidu 1.5 新版本在多个方面展现出了卓越的性能和创新的特点。首先,它…...
CentOS 7 aarch64停止更新后安装gcc8 —— 筑梦之路
CentOS 7.9非X86架构系统生命周期结束后(2024-6-30)配置在线可用yum源 —— 筑梦之路_centos7.9 arm-CSDN博客 以前的做法 sudo yum install centos-release-scl-rh sudo yum install devtoolset-8-buildsudo yum install devtoolset-8-gdb sudo yum i…...
WPF下 DataGrid加入序号列
先上代码: <DataGrid Name"DGV" AutoGenerateColumns"False" Grid.Row"0" Grid.Column"0" HorizontalGridLinesBrush"RoyalBlue" VerticalGridLinesBrush"Tomato" CanUserAddRows"False&qu…...
iOS UI 自动化 手势右滑退出当前页面
1、TouchAction from appium.webdriver.common.touch_action import TouchAction# 获取屏幕的宽度和高度 screen_width driver.get_window_size()["width"] screen_height driver.get_window_size()["height"]# 定义滑动的起点和终点坐标 start_x 0 en…...
《MySQL 实战教程:从零开始到高手进阶》
当然可以。下面是一篇关于MySQL的学习指南,它适合初学者到中级用户,涵盖了MySQL的基础知识、安装步骤、基本命令以及一些高级功能。 MySQL 学习指南 1. 了解 MySQL MySQL 是一个关系型数据库管理系统(RDBMS),由瑞典…...
第27天 安全开发-PHP应用TP 框架路由访问对象操作内置过滤绕过核心漏洞
时间轴 演示案例 TP 框架-开发-配置架构&路由&MVC 模型 TP 框架-安全-不安全写法&版本过滤绕过 TP 框架-开发-配置架构&路由&MVC 模型 参考: https://www.kancloud.cn/manual/thinkphp5_1 1、配置架构-导入使用 去thinkphp官网可以看到&…...
应用系统开发(12) Zync中实现数字相敏检波
在 Xilinx Zynq 系列(如 Zynq-7000 或 Zynq UltraScale+)中实现数字相敏检波(DSP,Digital Synchronous Detection)可以通过硬件(PL部分,FPGA逻辑)和软件(PS部分,ARM Cortex-A 处理器)的协同工作来实现。以下是一个详细的设计方法,包括基本原理和 Zynq 的实现步骤。…...
栈Stack和队列Queue
目录 一、栈 (1)用数组实现 (2)用单链表实现 (3)用标注尾结点的单链表实现 (4)用双向链表实现 2、栈的实际应用 (1)改变元素的序列 (2&am…...
uniapp 微信小程序地图标记点、聚合点/根据缩放重合点,根据缩放登记显示气泡marik标点
如图,如果要实现上方的效果: 上方两个效果根据经纬度标记点缩放后有重复点会添加数量 用到的文档地址https://developers.weixin.qq.com/miniprogram/dev/api/media/map/MapContext.addMarkers.htmlMapContext.addMarkers(Object object) 添加标记点Ma…...
Percona XtraBackup备份docker版本mysql 5.7
my.cnf配置文件 [client] default_character_setutf8[mysqld] # 数据存储目录(必须手动指定) datadir/var/lib/mysql/data# 字符集 collation_server utf8_general_ci character_set_server utf8 # 二进制日志 server-id1 log_bin/var/log/mysql/binl…...
C++:关联式容器的介绍及map与set的使用
我们之前已经学习过string,vector,list,queue,priority_queue等容器,这些容器我们统称为序列式容器,因为它们的数据的逻辑结构呈线性。因为这些容器中存储的数据即便二者之间发生交换,也不会对原有的容器结构造成太大影响。 但上篇文章我们介…...
一文说清:Linux下C++静态库的封装和调用
一 引言 《一文说清:windows下C静态库的封装和调用》中说了: 静态库允许开发者在多个项目中复用代码,减少重复劳动,并增强程序的可维护性。并讲述了windows环境下创建、封装以及调用C静态库的过程。 本文则描述了,如…...
【Java 学习】数据类型、变量、运算符、条件控制语句
Java基础语法 1. 打印 Hello World !2. 变量类和数据类型2.1 什么是变量?什么是数据类型?2.2 常用的数据类型2.3 使用变量2.4 String 类数据类型2.4.1 String 类基本概念2.4.2 String 类的使用 3. 运算符3.1 算数运算符3.2 关系运算符3.3 逻辑运算符3.4 …...
Linux应用开发之网络套接字编程(实例篇)
服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...
Flask RESTful 示例
目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题: 下面创建一个简单的Flask RESTful API示例。首先,我们需要创建环境,安装必要的依赖,然后…...
label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...
生成 Git SSH 证书
🔑 1. 生成 SSH 密钥对 在终端(Windows 使用 Git Bash,Mac/Linux 使用 Terminal)执行命令: ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" 参数说明: -t rsa&#x…...
相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...
Python如何给视频添加音频和字幕
在Python中,给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加,包括必要的代码示例和详细解释。 环境准备 在开始之前,需要安装以下Python库:…...
c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...
优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...
