当前位置: 首页 > news >正文

关于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主要成员变量

threadTaskCountAtomicInteger,用于记录当前正在处理的任务数

private final AtomicInteger threadTaskCount = new AtomicInteger(0);

executorThreadPoolExecutor,用于并发处理文件解析任务

private final ThreadPoolExecutor executor = new ThreadPoolExecutor(20, 20, 5, TimeUnit.SECONDS, new LinkedBlockingDeque<>());

dataListCopyOnWriteArrayList,用于存储解析后的数据对象

private final List<OdsResidentRecordExcelData> dataList = new CopyOnWriteArrayList<>();

successFileListfailFileListsynchronizedList,用于存储成功和失败的文件路径。

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列表&#xff08;二维表格&#xff09;的入库处理&#xff0c;一般的mysql连接工具&#xff0c;例如Navicat就支持。但是&#xff0c;因为业务需要&#xff0c;不想每次都去手动导入&#xff0c;所以这里采用编码且定时任务的形式来实现。 2.Excel常规列…...

深入理解 JavaScript 中的 Array.find() 方法:原理、性能优势与实用案例详解

目录 深入理解 JavaScript 中的 Array.find() 方法&#xff1a;原理、性能优势与实用案例详解 一、引言&#xff1a;为什么要使用Array.find() 二、Array.find()的使用与技巧 1、基础语法 2、返回值 3、使用技巧 三、Array.find()的优势与实际应用案例 1、利用返回引用…...

计算机网络安全 —— 对称加密算法 DES (一)

一、对称加密算法概念# ​ 我们通过计算机网络传输数据时&#xff0c;如果无法防止他人窃听&#xff0c; 可以利用密码学技术将发送的数据变换成对任何不知道如何做逆变换的人都不可理解的形式&#xff0c; 从而保证了数据的机密性。这种变换被称为加密&#xff08; encryptio…...

5. ARM_指令集

概述 分类 汇编中的符号&#xff1a; 指令&#xff1a;能够编译生成一条32位机器码&#xff0c;并且能被处理器识别和执行伪指令&#xff1a;本身不是指令&#xff0c;编译器可以将其替换成若干条指令伪操作&#xff1a;不会生成指令&#xff0c;只是在编译阶段告诉编译器怎…...

Jenkins的pipeline Script的 每个组件的详细讲解

在Jenkins的Pipeline脚本中&#xff0c;各个组件的配置和Groovy的一些常用函数起到了决定性的作用&#xff0c;帮助开发人员控制自动化流程的执行。以下是对Jenkins Pipeline的主要组件和Groovy常用函数的详细讲解&#xff1a; 1. Jenkins Pipeline主要组件 1.1 agent 功能&…...

Tomcat 和 Netty 的区别及应用场景分析

在 Java Web 开发中&#xff0c;Tomcat 和 Netty 都是常见的网络框架&#xff0c;它们各自有着不同的设计理念和适用场景。本文将通过详细的对比和实际场景示例&#xff0c;帮助你理解 Tomcat 和 Netty 在功能、性能、架构等方面的差异&#xff0c;帮助你在实际开发中做出更合理…...

6.C操作符详解,深入探索操作符与字符串处理

C操作符详解&#xff0c;深入探索操作符与字符串处理 C语言往期系列文章目录 往期回顾&#xff1a; C语言是什么&#xff1f;编程界的‘常青树’&#xff0c;它的辉煌你不可不知VS 2022 社区版C语言的安装教程&#xff0c;不要再卡在下载0B/s啦C语言入门&#xff1a;解锁基础…...

生数科技发布 Vidu 1.5 新版本,引领视频大模型新潮流

在国内视频大模型领域&#xff0c;生数科技一直以创新和突破而备受瞩目。近日&#xff0c;生数科技再度发力&#xff0c;发布了 Vidu 1.5 新版本&#xff0c;为视频创作带来了全新的变革与机遇。 Vidu 1.5 新版本在多个方面展现出了卓越的性能和创新的特点。首先&#xff0c;它…...

CentOS 7 aarch64停止更新后安装gcc8 —— 筑梦之路

CentOS 7.9非X86架构系统生命周期结束后&#xff08;2024-6-30&#xff09;配置在线可用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加入序号列

先上代码&#xff1a; <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的学习指南&#xff0c;它适合初学者到中级用户&#xff0c;涵盖了MySQL的基础知识、安装步骤、基本命令以及一些高级功能。 MySQL 学习指南 1. 了解 MySQL MySQL 是一个关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;由瑞典…...

第27天 安全开发-PHP应用TP 框架路由访问对象操作内置过滤绕过核心漏洞

时间轴 演示案例 TP 框架-开发-配置架构&路由&MVC 模型 TP 框架-安全-不安全写法&版本过滤绕过 TP 框架-开发-配置架构&路由&MVC 模型 参考&#xff1a; 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

目录 一、栈 &#xff08;1&#xff09;用数组实现 &#xff08;2&#xff09;用单链表实现 &#xff08;3&#xff09;用标注尾结点的单链表实现 &#xff08;4&#xff09;用双向链表实现 2、栈的实际应用 &#xff08;1&#xff09;改变元素的序列 &#xff08;2&am…...

uniapp 微信小程序地图标记点、聚合点/根据缩放重合点,根据缩放登记显示气泡marik标点

如图&#xff0c;如果要实现上方的效果&#xff1a; 上方两个效果根据经纬度标记点缩放后有重复点会添加数量 用到的文档地址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] # 数据存储目录&#xff08;必须手动指定&#xff09; 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等容器&#xff0c;这些容器我们统称为序列式容器&#xff0c;因为它们的数据的逻辑结构呈线性。因为这些容器中存储的数据即便二者之间发生交换&#xff0c;也不会对原有的容器结构造成太大影响。 但上篇文章我们介…...

一文说清:Linux下C++静态库的封装和调用

一 引言 《一文说清&#xff1a;windows下C静态库的封装和调用》中说了&#xff1a; 静态库允许开发者在多个项目中复用代码&#xff0c;减少重复劳动&#xff0c;并增强程序的可维护性。并讲述了windows环境下创建、封装以及调用C静态库的过程。 本文则描述了&#xff0c;如…...

【Java 学习】数据类型、变量、运算符、条件控制语句

Java基础语法 1. 打印 Hello World !2. 变量类和数据类型2.1 什么是变量&#xff1f;什么是数据类型&#xff1f;2.2 常用的数据类型2.3 使用变量2.4 String 类数据类型2.4.1 String 类基本概念2.4.2 String 类的使用 3. 运算符3.1 算数运算符3.2 关系运算符3.3 逻辑运算符3.4 …...

后进先出(LIFO)详解

LIFO 是 Last In, First Out 的缩写&#xff0c;中文译为后进先出。这是一种数据结构的工作原则&#xff0c;类似于一摞盘子或一叠书本&#xff1a; 最后放进去的元素最先出来 -想象往筒状容器里放盘子&#xff1a; &#xff08;1&#xff09;你放进的最后一个盘子&#xff08…...

第25节 Node.js 断言测试

Node.js的assert模块主要用于编写程序的单元测试时使用&#xff0c;通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试&#xff0c;通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

Caliper 配置文件解析:config.yaml

Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...

ios苹果系统,js 滑动屏幕、锚定无效

现象&#xff1a;window.addEventListener监听touch无效&#xff0c;划不动屏幕&#xff0c;但是代码逻辑都有执行到。 scrollIntoView也无效。 原因&#xff1a;这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作&#xff0c;从而会影响…...

RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 本文全面剖析RNN核心原理&#xff0c;深入讲解梯度消失/爆炸问题&#xff0c;并通过LSTM/GRU结构实现解决方案&#xff0c;提供时间序列预测和文本生成…...

AI书签管理工具开发全记录(十九):嵌入资源处理

1.前言 &#x1f4dd; 在上一篇文章中&#xff0c;我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源&#xff0c;方便后续将资源打包到一个可执行文件中。 2.embed介绍 &#x1f3af; Go 1.16 引入了革命性的 embed 包&#xff0c;彻底改变了静态资源管理的…...

JVM虚拟机:内存结构、垃圾回收、性能优化

1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

C++ 设计模式 《小明的奶茶加料风波》

&#x1f468;‍&#x1f393; 模式名称&#xff1a;装饰器模式&#xff08;Decorator Pattern&#xff09; &#x1f466; 小明最近上线了校园奶茶配送功能&#xff0c;业务火爆&#xff0c;大家都在加料&#xff1a; 有的同学要加波霸 &#x1f7e4;&#xff0c;有的要加椰果…...

离线语音识别方案分析

随着人工智能技术的不断发展&#xff0c;语音识别技术也得到了广泛的应用&#xff0c;从智能家居到车载系统&#xff0c;语音识别正在改变我们与设备的交互方式。尤其是离线语音识别&#xff0c;由于其在没有网络连接的情况下仍然能提供稳定、准确的语音处理能力&#xff0c;广…...