当前位置: 首页 > 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 …...

【软考】系统架构设计师-数据库设计基础

数据库核心考点 三级模式-两级映射 外模式--视图 概念模式--表&#xff08;模式、基本表&#xff09; 内模式--物理文件 数据库设计 概念结构设计&#xff1a;属性冲突、命名冲突、结构冲突 逻辑结构设计&#xff1a;关系模式&#xff08;层次模型、网络模型&#xff09…...

【Jmeter相关】

Jmeter 可以作为接口测试问题&#xff0c;也会涉及到性能相关的问题 一、JMeter中用户定义的变量(User Defined Variables&#xff09;和用户参 数&#xff08;User Parameters&#xff09;的区别是什么? 在JMeter中都是用于定义和存储测试数据的方法&#xff0c;但它们有一…...

拍立淘按图搜索API接口系列,返回示例图参考

拍立淘按图搜索API接口允许用户通过上传图片来搜索相似的商品&#xff0c;该接口返回的通常是一个JSON格式的响应&#xff0c;其中包含了与上传图片相似的商品信息。以下是一个基于淘宝平台的拍立淘按图搜索API接口返回数据的JSON格式示例&#xff0c;同时提供对其关键字段的解…...

OSG开发笔记(三十二):深入理解相机视口、制作支持与主视图同步变换旋转的相机HUD

​若该文为原创文章&#xff0c;未经允许不得转载 本文章博客地址&#xff1a;https://blog.csdn.net/qq21497936/article/details/143852695 各位读者&#xff0c;知识无穷而人力有穷&#xff0c;要么改需求&#xff0c;要么找专业人士&#xff0c;要么自己研究 长沙红胖子Qt…...

2024RISC-V中国峰会 演讲幻灯片和视频回放均已公开

目录 一、幻灯片地址: 二、演讲视频: 一、幻灯片地址: RVSC2024/slides at main cnrv/RVSC2024 GitHub 二、演讲视频: RISC-V国际基金会的个人空间-RISC-V国际基金会个人主页-哔哩哔哩视频...

河道无人机雷达测流监测系统由哪几部分组成?

在现代水利管理中&#xff0c;河道无人机雷达监测系统正逐渐成为一种重要的工具&#xff0c;为河道的安全和管理提供了强大的技术支持。那么&#xff0c;这个先进的监测系统究竟由哪几部分组成呢&#xff1f; 河道无人机雷达监测系统工作原理 雷达传感器通过发射电磁波或激光束…...

28.<Spring博客系统⑤(部署的整个过程(CentOS))>

引入依赖 Spring-boot-maven-plugin 用maven进行打包的时候必须用到这个插件。看看自己pom.xml中有没有这个插件 并且看看配置正确不正常。 注&#xff1a;我们这个项目打的jar包在30MB左右。 <plugin><groupId>org.springframework.boot</groupId><artif…...

OpenAI震撼发布:桌面版ChatGPT,Windows macOS双平台AI编程体验!

【雪球导读】 「OpenAI推出ChatGPT桌面端」 OpenAI重磅推出ChatGPT桌面端&#xff0c;全面支持Windows和macOS系统&#xff01;这款新工具为用户在日常生活和工作中提供了前所未有的无缝交互体验。对于那些依赖桌面端进行开发工作的专业人士来说&#xff0c;这一更新带来了令人…...

香港站群服务器有助于提升网站在搜索引擎中的排名

拥有253个IP的服务器通常被称为多IP站群服务器。这种服务器架构主要用于集中管理多个网站&#xff0c;允许网站管理员通过一个后台管理系统来高效管理和更新这些网站。 一、主要特点 集中管理&#xff1a;多IP站群服务器通过统一的后台管理系统&#xff0c;可以实现对多个网站…...

YOLOX:使用自己数据集训练模型及改进--1.YOLOX环境搭建及运行

YOLOX环境搭建及运行 YOLO X网络架构是继YOLO v5后,由旷视科技于2021年提出的新一代anthor-free模型,研究者将网络分为输入端、Backbone、PAFPN及Predication,并在Predication提出Decoupled Head、Anchor-free和Multi positives(后文会详细介绍)。 本篇文章介绍如何通过官…...

wordpress十佳主题/做网络推广需要多少钱

win7下&#xff0c;管理员模式&#xff0c;用sc delete 服务名 删除所有mysql服务。删除C:/ProgramData和C:/Users/opps/AppData/Roaming的mysql文件夹删除。以下是转载的方法&#xff0c;最好按照这个方法再清理以下注册表。1。在“运行”里键入regedit进入注册表。2。HEKY_LO…...

服务器ip做网站/企业网站建设的作用

为什么80%的码农都做不了架构师&#xff1f;>>> 通过为防火墙提供有关对来自某个源&#xff0c;到某个目的地或具有特定协议类型的信息包要执行操作的指令及规则控制信息包的过滤。通过使用Netfilter/iptables系统提供的特殊命令iptables建立这些规则&#xff0c;并…...

网站建设知名公司排名/免费推广网站注册入口

bug错误类型我想知道为什么我们将编程故障和错误称为“错误” 。 所以我做了一些快速研究。 1.托马斯爱迪生 托马斯爱迪生&#xff08;Thomas Edison&#xff09;在1878年给同事的一封信中写了以下几句话&#xff1a; 在我的所有发明中都是如此。 第一步是直觉&#xff0c;突…...

哪个网站可以做担保交易/广告营销策略

重新看《JavaScript设计模式与开发实践》一书&#xff0c;第32页发现个简易版的Function.prototype.bind实现&#xff0c;非常容易理解&#xff0c;记录在这了。 Function.prototype.bind function (context) {var self this;return function () {return self.apply(context,…...

哪个网站做相片书好/天津百度搜索网站排名

伯乐一看小编的这个博文的标题是不是觉得有些小&#xff0c;以点到面&#xff0c;知道了web中getContextPath()这种获取路径的方式&#xff0c;显然其他的方式的是可以以此类推的。常说&#xff0c;工作学习找共同点嘛。 上一段我们也提高getContextPath()的含义&#xff0c;是…...

做网站的英文/东莞网络推广营销

ParallelsDesktop安装DOS7.1并与MAC共享文件 Table of Contents 1. 在Parallels Desktop中安装DOS7.12. 配置与Mac共享文件1 在Parallels Desktop中安装DOS7.1 准备一个DOS7.1的ISO安装镜像&#xff0c;有些朋友是img的文件&#xff0c;pd是不认识的。 安装时&#xff0c;选择其…...