关于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 …...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...
谷歌浏览器插件
项目中有时候会用到插件 sync-cookie-extension1.0.0:开发环境同步测试 cookie 至 localhost,便于本地请求服务携带 cookie 参考地址:https://juejin.cn/post/7139354571712757767 里面有源码下载下来,加在到扩展即可使用FeHelp…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...
sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!
简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求,并检查收到的响应。它以以下模式之一…...
RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)
RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发,后来由Pivotal Software Inc.(现为VMware子公司)接管。RabbitMQ 是一个开源的消息代理和队列服务器,用 Erlang 语言编写。广泛应用于各种分布…...
Python第七周作业
Python第七周作业 文章目录 Python第七周作业 1.使用open以只读模式打开文件data.txt,并逐行打印内容 2.使用pathlib模块获取当前脚本的绝对路径,并创建logs目录(若不存在) 3.递归遍历目录data,输出所有.csv文件的路径…...
Copilot for Xcode (iOS的 AI辅助编程)
Copilot for Xcode 简介Copilot下载与安装 体验环境要求下载最新的安装包安装登录系统权限设置 AI辅助编程生成注释代码补全简单需求代码生成辅助编程行间代码生成注释联想 代码生成 总结 简介 尝试使用了Copilot,它能根据上下文补全代码,快速生成常用…...
python可视化:俄乌战争时间线关键节点与深层原因
俄乌战争时间线可视化分析:关键节点与深层原因 俄乌战争是21世纪欧洲最具影响力的地缘政治冲突之一,自2022年2月爆发以来已持续超过3年。 本文将通过Python可视化工具,系统分析这场战争的时间线、关键节点及其背后的深层原因,全面…...
华为OD机考- 简单的自动曝光/平均像素
import java.util.Arrays; import java.util.Scanner;public class DemoTest4 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint[] arr Array…...
