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

EasyExcel的源码流程(导入Excel)

1. 入口

2.  EasyExcel类继承了EasyExcelFactory类,EasyExcel自动拥有EasyExcelFactory父类的所有方法,如read(),readSheet(),write(),writerSheet()等等。

3. 进入.read()方法,需要传入三个参数(文件路径,表头映射类,read监听器)
   首先调用new ExcelReaderBuilder()方法,初始化ReadWorkbook对象
   设置完readWorkbook属性后调,返回excelReaderBuilder对象 

4. 这里又个传入的参数是read监听器,进入其内部看一下,我们自定义了PersonListener实现了ReadListener。ReadListener接口源码 :

自定义的PersonListener类:

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.aliyun.odps.jdbc.utils.LoggerFactory;
import org.springframework.stereotype.Component;import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;@Component
public class PersonListener extends AnalysisEventListener<PersonTest> {//一行一行读出excel内容  不读表头  EasyExcel之所以效率高,也是因它一行一行读取,解析。@Overridepublic void invoke(PersonTest personTest, AnalysisContext analysisContext) {System.out.println("***"+personTest);}//读取表头@Overridepublic void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {System.out.println("表头"+headMap);}//读取完执行的方法@Overridepublic void doAfterAllAnalysed(AnalysisContext analysisContext) {System.out.println("读取全部后执行");}
}

5. 接下来调用的是.sheet()方法,这里我们会传入sheetNo、sheetName参数,调用build()方法创建ExcelReader对象,传入ExcelReaderSheetBuilder构造方法中,最终创ExcelReaderSheetBuilder对象 

6. 进入build()方法,build()方法生成了ExcelReader对象,初始化ExcelAnalyser,并实例化ExcelAnalyser。

在实例化ExcelAnalyser时,choiceExcelExecutor()方法通过excel格式使用不同的执行器。
我们看XLSX中,初始化了XlsxReadContext上下文对象,给到analysisContext,又初始化了XlsxSaxAnalyser解析器对象 

public class ExcelAnalyserImpl implements ExcelAnalyser {private static final Logger LOGGER = LoggerFactory.getLogger(ExcelAnalyserImpl.class);private AnalysisContext analysisContext;private ExcelReadExecutor excelReadExecutor;/*** Prevent multiple shutdowns*/private boolean finished = false;public ExcelAnalyserImpl(ReadWorkbook readWorkbook) {try {choiceExcelExecutor(readWorkbook);} catch (RuntimeException e) {finish();throw e;} catch (Throwable e) {finish();throw new ExcelAnalysisException(e);}}private void choiceExcelExecutor(ReadWorkbook readWorkbook) throws Exception {ExcelTypeEnum excelType = ExcelTypeEnum.valueOf(readWorkbook);switch (excelType) {case XLS:POIFSFileSystem poifsFileSystem;if (readWorkbook.getFile() != null) {poifsFileSystem = new POIFSFileSystem(readWorkbook.getFile());} else {poifsFileSystem = new POIFSFileSystem(readWorkbook.getInputStream());}// So in encrypted excel, it looks like XLS but it's actually XLSXif (poifsFileSystem.getRoot().hasEntry(Decryptor.DEFAULT_POIFS_ENTRY)) {InputStream decryptedStream = null;try {decryptedStream = DocumentFactoryHelper.getDecryptedStream(poifsFileSystem.getRoot().getFileSystem(), readWorkbook.getPassword());XlsxReadContext xlsxReadContext = new DefaultXlsxReadContext(readWorkbook, ExcelTypeEnum.XLSX);analysisContext = xlsxReadContext;excelReadExecutor = new XlsxSaxAnalyser(xlsxReadContext, decryptedStream);return;} finally {IOUtils.closeQuietly(decryptedStream);// as we processed the full stream already, we can close the filesystem here// otherwise file handles are leakedpoifsFileSystem.close();}}if (readWorkbook.getPassword() != null) {Biff8EncryptionKey.setCurrentUserPassword(readWorkbook.getPassword());}XlsReadContext xlsReadContext = new DefaultXlsReadContext(readWorkbook, ExcelTypeEnum.XLS);xlsReadContext.xlsReadWorkbookHolder().setPoifsFileSystem(poifsFileSystem);analysisContext = xlsReadContext;excelReadExecutor = new XlsSaxAnalyser(xlsReadContext);break;case XLSX:XlsxReadContext xlsxReadContext = new DefaultXlsxReadContext(readWorkbook, ExcelTypeEnum.XLSX);analysisContext = xlsxReadContext;excelReadExecutor = new XlsxSaxAnalyser(xlsxReadContext, null);break;case CSV:CsvReadContext csvReadContext = new DefaultCsvReadContext(readWorkbook, ExcelTypeEnum.CSV);analysisContext = csvReadContext;excelReadExecutor = new CsvExcelReadExecutor(csvReadContext);break;default:break;}}
/*
----------------------------------------略---------------------------------------------
*/
}

7. XlsxSaxAnalyser详解

    7.1 进入new XlsxSaxAnalyser(xlsxReadContext, null)方法看一下,这里使用到SAX模式模式解析excel

public XlsxSaxAnalyser(XlsxReadContext xlsxReadContext, InputStream decryptedStream) throws Exception {this.xlsxReadContext = xlsxReadContext;// 初始化缓存(cache)XlsxReadWorkbookHolder xlsxReadWorkbookHolder = xlsxReadContext.xlsxReadWorkbookHolder();OPCPackage pkg = readOpcPackage(xlsxReadWorkbookHolder, decryptedStream);xlsxReadWorkbookHolder.setOpcPackage(pkg);// Read the Shared information StringsPackagePart sharedStringsTablePackagePart = pkg.getPart(SHARED_STRINGS_PART_NAME);if (sharedStringsTablePackagePart != null) {// 指定默认缓存defaultReadCache(xlsxReadWorkbookHolder, sharedStringsTablePackagePart);// 分析sharedStringsTable.xml,解析excel所有数据到readCacheanalysisSharedStringsTable(sharedStringsTablePackagePart.getInputStream(), xlsxReadWorkbookHolder);}XSSFReader xssfReader = new XSSFReader(pkg);analysisUse1904WindowDate(xssfReader, xlsxReadWorkbookHolder);// 设置样式表setStylesTable(xlsxReadWorkbookHolder, xssfReader);sheetList = new ArrayList<>();sheetMap = new HashMap<>();commentsTableMap = new HashMap<>();Map<Integer, PackageRelationshipCollection> packageRelationshipCollectionMap = MapUtils.newHashMap();xlsxReadWorkbookHolder.setPackageRelationshipCollectionMap(packageRelationshipCollectionMap);// 获取所有sheet页XSSFReader.SheetIterator ite = (XSSFReader.SheetIterator)xssfReader.getSheetsData();int index = 0;if (!ite.hasNext()) {throw new ExcelAnalysisException("Can not find any sheet!");}// 遍历sheet页while (ite.hasNext()) {InputStream inputStream = ite.next();// 保存所有sheet页sheetList.add(new ReadSheet(index, ite.getSheetName()));// 保存所有sheet页的输入流sheetMap.put(index, inputStream);if (xlsxReadContext.readWorkbookHolder().getExtraReadSet().contains(CellExtraTypeEnum.COMMENT)) {CommentsTable commentsTable = ite.getSheetComments();if (null != commentsTable) {commentsTableMap.put(index, commentsTable);}}if (xlsxReadContext.readWorkbookHolder().getExtraReadSet().contains(CellExtraTypeEnum.HYPERLINK)) {PackageRelationshipCollection packageRelationshipCollection = Optional.ofNullable(ite.getSheetPart()).map(packagePart -> {try {return packagePart.getRelationships();} catch (InvalidFormatException e) {log.warn("Reading the Relationship failed", e);return null;}}).orElse(null);if (packageRelationshipCollection != null) {packageRelationshipCollectionMap.put(index, packageRelationshipCollection);}}index++;}}

    7.2 进入analysisSharedStringsTable方法,可以看到创建了一个SharedStringsTableHandler处理器

    7.3 再进入parseXmlSource看到xmlReader.setContentHandler(handler)这一行代码,设置了SharedStringsTableHandler处理器

private void parseXmlSource(InputStream inputStream, ContentHandler handler) {InputSource inputSource = new InputSource(inputStream);try {SAXParserFactory saxFactory;String xlsxSAXParserFactoryName = xlsxReadContext.xlsxReadWorkbookHolder().getSaxParserFactoryName();if (StringUtils.isEmpty(xlsxSAXParserFactoryName)) {saxFactory = SAXParserFactory.newInstance();} else {saxFactory = SAXParserFactory.newInstance(xlsxSAXParserFactoryName, null);}try {saxFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);} catch (Throwable ignore) {}try {saxFactory.setFeature("http://xml.org/sax/features/external-general-entities", false);} catch (Throwable ignore) {}try {saxFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);} catch (Throwable ignore) {}SAXParser saxParser = saxFactory.newSAXParser();XMLReader xmlReader = saxParser.getXMLReader();xmlReader.setContentHandler(handler);xmlReader.parse(inputSource);inputStream.close();} catch (IOException | ParserConfigurationException | SAXException e) {throw new ExcelAnalysisException(e);} finally {if (inputStream != null) {try {inputStream.close();} catch (IOException e) {throw new ExcelAnalysisException("Can not close 'inputStream'!");}}}}

    7.4 我们将断点打在SharedStringsTableHandler里,发现下一步进入到这里面的startElement()    starteElement()后会调用endElement()

    7.5 反复调用,excel所有数据读取到readcache中

8. 调用.doRead()方法,开始SAX解析

    8.1 进入build()方法

    8.2 build()执行完后,执行read()方法,read()里还会进入一次read() 

9. 调用ExcelAnalyserImpl里的analysis()方法,设置sheetList,并调用执行器开始执行解析 

    9.1 调用的XlsxSaxAnalyser解析器execute()

 10. 进入parseXmlSource()方法,发现和之前的sax差不多,但只两次传入的handler类型不同,还是看一下传入的ContentHandler参数具体实现,进入XlsxRowHandler 内部

public class XlsxRowHandler extends DefaultHandler {private final XlsxReadContext xlsxReadContext;private static final Map<String, XlsxTagHandler> XLSX_CELL_HANDLER_MAP = new HashMap<String, XlsxTagHandler>(32);static {CellFormulaTagHandler cellFormulaTagHandler = new CellFormulaTagHandler();XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.CELL_FORMULA_TAG, cellFormulaTagHandler);XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.X_CELL_FORMULA_TAG, cellFormulaTagHandler);CellInlineStringValueTagHandler cellInlineStringValueTagHandler = new CellInlineStringValueTagHandler();XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.CELL_INLINE_STRING_VALUE_TAG, cellInlineStringValueTagHandler);XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.X_CELL_INLINE_STRING_VALUE_TAG, cellInlineStringValueTagHandler);CellTagHandler cellTagHandler = new CellTagHandler();XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.CELL_TAG, cellTagHandler);XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.X_CELL_TAG, cellTagHandler);CellValueTagHandler cellValueTagHandler = new CellValueTagHandler();XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.CELL_VALUE_TAG, cellValueTagHandler);XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.X_CELL_VALUE_TAG, cellValueTagHandler);CountTagHandler countTagHandler = new CountTagHandler();XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.DIMENSION_TAG, countTagHandler);XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.X_DIMENSION_TAG, countTagHandler);HyperlinkTagHandler hyperlinkTagHandler = new HyperlinkTagHandler();XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.HYPERLINK_TAG, hyperlinkTagHandler);XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.X_HYPERLINK_TAG, hyperlinkTagHandler);MergeCellTagHandler mergeCellTagHandler = new MergeCellTagHandler();XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.MERGE_CELL_TAG, mergeCellTagHandler);XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.X_MERGE_CELL_TAG, mergeCellTagHandler);RowTagHandler rowTagHandler = new RowTagHandler();XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.ROW_TAG, rowTagHandler);XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.X_ROW_TAG, rowTagHandler);}public XlsxRowHandler(XlsxReadContext xlsxReadContext) {this.xlsxReadContext = xlsxReadContext;}@Overridepublic void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException {XlsxTagHandler handler = XLSX_CELL_HANDLER_MAP.get(name);if (handler == null || !handler.support(xlsxReadContext)) {return;}xlsxReadContext.xlsxReadSheetHolder().getTagDeque().push(name);handler.startElement(xlsxReadContext, name, attributes);}@Overridepublic void characters(char[] ch, int start, int length) throws SAXException {String currentTag = xlsxReadContext.xlsxReadSheetHolder().getTagDeque().peek();if (currentTag == null) {return;}XlsxTagHandler handler = XLSX_CELL_HANDLER_MAP.get(currentTag);if (handler == null || !handler.support(xlsxReadContext)) {return;}handler.characters(xlsxReadContext, ch, start, length);}@Overridepublic void endElement(String uri, String localName, String name) throws SAXException {XlsxTagHandler handler = XLSX_CELL_HANDLER_MAP.get(name);if (handler == null || !handler.support(xlsxReadContext)) {return;}handler.endElement(xlsxReadContext, name);xlsxReadContext.xlsxReadSheetHolder().getTagDeque().pop();}}

    10.1 startElement()和endElement()都有多种实现

11. 进入用到的重要的几个类CellTagHandler、RowTagHandler

CellTagHandler: 读取cell的值,并放入tempCellData

public void startElement(XlsxReadContext xlsxReadContext, String name, Attributes attributes) {XlsxReadSheetHolder xlsxReadSheetHolder = xlsxReadContext.xlsxReadSheetHolder();xlsxReadSheetHolder.setColumnIndex(PositionUtils.getCol(attributes.getValue(ExcelXmlConstants.ATTRIBUTE_R),xlsxReadSheetHolder.getColumnIndex()));// t="s" ,it means String// t="str" ,it means String,but does not need to be read in the 'sharedStrings.xml'// t="inlineStr" ,it means String,but does not need to be read in the 'sharedStrings.xml'// t="b" ,it means Boolean// t="e" ,it means Error// t="n" ,it means Number// t is null ,it means Empty or NumberCellDataTypeEnum type = CellDataTypeEnum.buildFromCellType(attributes.getValue(ExcelXmlConstants.ATTRIBUTE_T));xlsxReadSheetHolder.setTempCellData(new ReadCellData<>(type));xlsxReadSheetHolder.setTempData(new StringBuilder());// Put in data transformation informationString dateFormatIndex = attributes.getValue(ExcelXmlConstants.ATTRIBUTE_S);int dateFormatIndexInteger;if (StringUtils.isEmpty(dateFormatIndex)) {dateFormatIndexInteger = DEFAULT_FORMAT_INDEX;} else {dateFormatIndexInteger = Integer.parseInt(dateFormatIndex);}xlsxReadSheetHolder.getTempCellData().setDataFormatData(xlsxReadContext.xlsxReadWorkbookHolder().dataFormatData(dateFormatIndexInteger));}@Overridepublic void endElement(XlsxReadContext xlsxReadContext, String name) {XlsxReadSheetHolder xlsxReadSheetHolder = xlsxReadContext.xlsxReadSheetHolder();ReadCellData<?> tempCellData = xlsxReadSheetHolder.getTempCellData();StringBuilder tempData = xlsxReadSheetHolder.getTempData();String tempDataString = tempData.toString();CellDataTypeEnum oldType = tempCellData.getType();switch (oldType) {case STRING:// In some cases, although cell type is a string, it may be an empty tagif (StringUtils.isEmpty(tempDataString)) {break;}String stringValue = xlsxReadContext.readWorkbookHolder().getReadCache().get(Integer.valueOf(tempDataString));tempCellData.setStringValue(stringValue);break;case DIRECT_STRING:case ERROR:tempCellData.setStringValue(tempDataString);tempCellData.setType(CellDataTypeEnum.STRING);break;case BOOLEAN:if (StringUtils.isEmpty(tempDataString)) {tempCellData.setType(CellDataTypeEnum.EMPTY);break;}tempCellData.setBooleanValue(BooleanUtils.valueOf(tempData.toString()));break;case NUMBER:case EMPTY:if (StringUtils.isEmpty(tempDataString)) {tempCellData.setType(CellDataTypeEnum.EMPTY);break;}tempCellData.setType(CellDataTypeEnum.NUMBER);tempCellData.setNumberValue(BigDecimal.valueOf(Double.parseDouble(tempDataString)));break;default:throw new IllegalStateException("Cannot set values now");}if (tempCellData.getStringValue() != null&& xlsxReadContext.currentReadHolder().globalConfiguration().getAutoTrim()) {tempCellData.setStringValue(tempCellData.getStringValue().trim());}tempCellData.checkEmpty();tempCellData.setRowIndex(xlsxReadSheetHolder.getRowIndex());tempCellData.setColumnIndex(xlsxReadSheetHolder.getColumnIndex());xlsxReadSheetHolder.getCellMap().put(xlsxReadSheetHolder.getColumnIndex(), tempCellData);}

RowTagHandler: 当一行读取完毕后,调用分析事件处理器,处理一行数据

                            xlsxReadContext.analysisEventProcessor().endRow(xlsxReadContext);

public void startElement(XlsxReadContext xlsxReadContext, String name, Attributes attributes) {XlsxReadSheetHolder xlsxReadSheetHolder = xlsxReadContext.xlsxReadSheetHolder();int rowIndex = PositionUtils.getRowByRowTagt(attributes.getValue(ExcelXmlConstants.ATTRIBUTE_R),xlsxReadSheetHolder.getRowIndex());Integer lastRowIndex = xlsxReadContext.readSheetHolder().getRowIndex();while (lastRowIndex + 1 < rowIndex) {xlsxReadContext.readRowHolder(new ReadRowHolder(lastRowIndex + 1, RowTypeEnum.EMPTY,xlsxReadSheetHolder.getGlobalConfiguration(), new LinkedHashMap<Integer, Cell>()));xlsxReadContext.analysisEventProcessor().endRow(xlsxReadContext);xlsxReadSheetHolder.setColumnIndex(null);xlsxReadSheetHolder.setCellMap(new LinkedHashMap<Integer, Cell>());lastRowIndex++;}xlsxReadSheetHolder.setRowIndex(rowIndex);}@Overridepublic void endElement(XlsxReadContext xlsxReadContext, String name) {XlsxReadSheetHolder xlsxReadSheetHolder = xlsxReadContext.xlsxReadSheetHolder();RowTypeEnum rowType = MapUtils.isEmpty(xlsxReadSheetHolder.getCellMap()) ? RowTypeEnum.EMPTY : RowTypeEnum.DATA;// It's possible that all of the cells in the row are emptyif (rowType == RowTypeEnum.DATA) {boolean hasData = false;for (Cell cell : xlsxReadSheetHolder.getCellMap().values()) {if (!(cell instanceof ReadCellData)) {hasData = true;break;}ReadCellData<?> readCellData = (ReadCellData<?>)cell;if (readCellData.getType() != CellDataTypeEnum.EMPTY) {hasData = true;break;}}if (!hasData) {rowType = RowTypeEnum.EMPTY;}}xlsxReadContext.readRowHolder(new ReadRowHolder(xlsxReadSheetHolder.getRowIndex(), rowType,xlsxReadSheetHolder.getGlobalConfiguration(), xlsxReadSheetHolder.getCellMap()));xlsxReadContext.analysisEventProcessor().endRow(xlsxReadContext);xlsxReadSheetHolder.setColumnIndex(null);xlsxReadSheetHolder.setCellMap(new LinkedHashMap<>());}

12. 进入endRow()方法

      endRow()里通过getIgnoreEmptyRow()来判断是否忽略空行(true为忽略,默认为true)

     想要设置IgnoreEmptyRow为false,可以在最初使用EasyExcel时设置:

13. 进入dealData()方法

private void dealData(AnalysisContext analysisContext) {ReadRowHolder readRowHolder = analysisContext.readRowHolder();Map<Integer, ReadCellData<?>> cellDataMap = (Map)readRowHolder.getCellMap();readRowHolder.setCurrentRowAnalysisResult(cellDataMap);int rowIndex = readRowHolder.getRowIndex();int currentHeadRowNumber = analysisContext.readSheetHolder().getHeadRowNumber();boolean isData = rowIndex >= currentHeadRowNumber;// Last head columnif (!isData && currentHeadRowNumber == rowIndex + 1) {buildHead(analysisContext, cellDataMap);}// Now is datafor (ReadListener readListener : analysisContext.currentReadHolder().readListenerList()) {try {if (isData) {readListener.invoke(readRowHolder.getCurrentRowAnalysisResult(), analysisContext);} else {readListener.invokeHead(cellDataMap, analysisContext);}} catch (Exception e) {onException(analysisContext, e);break;}if (!readListener.hasNext(analysisContext)) {throw new ExcelAnalysisStopException();}}}

14. dealData()方法中的invoke方法会执行ModelBuildEventListener里的invoke()方法,在这里会进行单行数据到实体类的映射,buildStringList()真正执行映射

15. 退回XlsxSaxAnalyser的解析器execute()方法

      进入readComments()方法,读取额外信息(批注、超链接、合并单元格信息读取)

	private void readComments(ReadSheet readSheet) {if (!xlsxReadContext.readWorkbookHolder().getExtraReadSet().contains(CellExtraTypeEnum.COMMENT)) {return;}CommentsTable commentsTable = commentsTableMap.get(readSheet.getSheetNo());if (commentsTable == null) {return;}Iterator<CellAddress> cellAddresses = commentsTable.getCellAddresses();while (cellAddresses.hasNext()) {CellAddress cellAddress = cellAddresses.next();XSSFComment cellComment = commentsTable.findCellComment(cellAddress);CellExtra cellExtra = new CellExtra(CellExtraTypeEnum.COMMENT, cellComment.getString().toString(),cellAddress.getRow(), cellAddress.getColumn());xlsxReadContext.readSheetHolder().setCellExtra(cellExtra);xlsxReadContext.analysisEventProcessor().extra(xlsxReadContext);}}

16. 最后进入.endSheet(xlsxReadContext)方法

@Overridepublic void endSheet(AnalysisContext analysisContext) {// 这里会调用所有监听器中的doAfterAllAnalysed方法,执行最后的操作for (ReadListener readListener : analysisContext.currentReadHolder().readListenerList()) {readListener.doAfterAllAnalysed(analysisContext);}}

17. 在读取完毕之后,执行finish()方法,关闭所有流 

相关文章:

EasyExcel的源码流程(导入Excel)

1. 入口 2. EasyExcel类继承了EasyExcelFactory类&#xff0c;EasyExcel自动拥有EasyExcelFactory父类的所有方法&#xff0c;如read()&#xff0c;readSheet()&#xff0c;write()&#xff0c;writerSheet()等等。 3. 进入.read()方法&#xff0c;需要传入三个参数(文件路径…...

基于 jasypt 实现spring boot 配置文件脱敏

前言 在项目构建过程中&#xff0c;保护敏感信息的安全性至关重要&#xff0c;为了提高系统的安全性能&#xff0c;我们采用了Jasypt来对配置文件中的敏感信息进行加密处理&#xff0c;以确保系统的机密信息不被轻易泄露。 步骤 添加Maven依赖 首先&#xff0c;我们需要添加…...

Python——ASCII编码与Unicode(UTF-8,UTF-16 和 UTF-32)编码

Python3 Python——ASCII编码与Unicode&#xff08;UTF-8&#xff0c;UTF-16 和 UTF-32&#xff09;编码 文章目录 Python3一、编码与编码格式二、ASCII编码与UTF-8编码&#xff08;UTF-16 和 UTF-32编码&#xff09;三、ASCII 字符串和 Unicode 字符串 最近看Python程序的文件…...

【多媒体技术与实践】音频信息获取和处理——编程题汇总

1&#xff1a;音频信息数据量计算 已知采样频率&#xff08;单位KHz&#xff09;、量化位数、声道数及持续时间&#xff08;单位分钟&#xff09;&#xff0c;求未压缩时的数据量&#xff08;单位MB&#xff09;. 例如&#xff1a; 输入&#xff1a; 22.05 16 2 3 &#xff…...

堆优化迪氏最短单源路径原理及C++实现

时间复杂度 O(ElogE)&#xff0c;E是边数。适用与稀疏图。 使用前提 边的权为正。可以非连通&#xff0c;非连通的距离为-1。 原理 优选队列&#xff08;小根堆&#xff09;记录两个数据&#xff1a;当前点到源点距离&#xff0c;当前点。先处理距离小的点&#xff1b;如果…...

Leetcode202. 快乐数

力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 编写一个算法来判断一个数 n 是不是快乐数。 「快乐数」 定义为&#xff1a; 对于一个正整数&#xff0c;每一次将该数替换为它每个位置上的数字的平方和。然后重复这个过程直到这个数变为 1&#xff0…...

【MySQL】MySql常见面试题总结

目录 一、什么是sql注入 二、sql语句的执行流程 三、内连接和外连接的区别 四、Union和Union All 有什么区别 五、MySql如何取差集 六、DELETE和TRUNCATE有什么区别 七、count&#xff08;*&#xff09;和count&#xff08;1&#xff09;的区别 八、MyISAM和InnoDB的区…...

【Java 进阶篇】JDBC PreparedStatement 详解

在Java中&#xff0c;与关系型数据库进行交互是非常常见的任务之一。JDBC&#xff08;Java Database Connectivity&#xff09;是Java平台的一个标准API&#xff0c;用于连接和操作各种关系型数据库。其中&#xff0c;PreparedStatement 是 JDBC 中一个重要的接口&#xff0c;用…...

嵌入式Linux应用开发-驱动大全-第一章同步与互斥①

嵌入式Linux应用开发-驱动大全-第一章同步与互斥① 第一章 同步与互斥①1.1 内联汇编1.1.1 C语言实现加法1.1.2 使用汇编函数实现加法1.1.3 内联汇编语法1.1.4 编写内联汇编实现加法1.1.5 earlyclobber的例子 1.2 同步与互斥的失败例子1.2.1 失败例子11.2.2 失败例子21.2.3 失败…...

【计算机网络】 基于UDP的简单通讯(客户端)

文章目录 客户端流程代码实现添加头文件以及库依赖加载库创建套接字发送接收数据关闭套接字、卸载库 测试 客户端 流程 客户端跟服务端差不多&#xff0c;也要先加载库&#xff0c;在加载库之后也要创建套接字&#xff0c;但是客户端一定是没有绑定ip地址的&#xff0c;之后是…...

【云备份项目】:环境搭建(g++、json库、bundle库、httplib库)

文章目录 1. g 升级到 7.3 版本2. 安装 jsoncpp 库3. 下载 bundle 数据压缩库4. 下载 httplib 库从 Win 传输文件到 Linux解压缩 1. g 升级到 7.3 版本 &#x1f517;链接跳转 2. 安装 jsoncpp 库 &#x1f517;链接跳转 3. 下载 bundle 数据压缩库 安装 git 工具 sudo yum…...

电脑右键新建记事本不见了--设置恢复篇(无需操作注册表)

电脑右键新建记事本不见了–设置恢复篇&#xff08;无需修改注册表&#xff09; 电脑不知怎么想右键新建记事本结果竟然不见了&#xff0c;搜寻网上的都是什么修改注册表&#xff0c;粘贴代码修复&#xff08;感觉太复杂了&#xff09;&#xff0c;这里介绍通过设置内重新对记…...

JavaScript内置对象 - Array数组(四)- 序列生成器

序列生成器是生成一个指定起始值和结束值的序列&#xff0c;并且根据指定间隔长度&#xff0c;生成序列数组。 完成此功能需要使用到Array内置对象的from()对象&#xff0c;以及类数组相关知识&#xff0c;前面几篇有相关案例进行演示。 地址一&#xff1a;JavaScript内置对象…...

GD32F103x IIC通信

1. IIC通信 1.IIC的介绍 IIC总线有两条串行线&#xff0c;其一是时钟线SCK&#xff08;同步&#xff09;&#xff0c;其二是数据线SDA。只有一条数据线属于半双工。应用中&#xff0c;单片机常常作为主机&#xff0c;外围器件可以挂载多个。&#xff08;当然主机也可以有多个。…...

什么是FOSS

FOSS 是指 自由和开放源码软件(Free and Open Source Software)。这并不意味着软件是免费的。它意味着软件的源代码是开放的&#xff0c;任何人都可以自由使用、研究和修改代码。这个原则允许人们像一个社区一样为软件的开发和改进做出贡献。...

C++语言GDAL批量裁剪多波段栅格图像:基于像元个数裁剪

本文介绍基于C 语言的GDAL模块&#xff0c;按照给定的像元行数与列数&#xff0c;批量裁剪大量多波段栅格遥感影像文件&#xff0c;并将所得到的裁剪后新的多波段遥感影像文件保存在指定路径中的方法。 在之前的文章中&#xff0c;我们多次介绍了在不同平台&#xff0c;或基于不…...

简单丝的tab切换栏(html/CSS)

#html <!DOCTYPE html> <html lang"en" > <head><meta charset"UTF-8"><title>CSS实现左右滑动选项卡效果</title><link rel"stylesheet" href"https://cdnjs.cloudflare.com/ajax/libs/meyer-res…...

LabVIEW开发带式谱感测技术

LabVIEW开发带式谱感测技术 如今&#xff0c;通过无线网络传输的数据量正在迅速增加&#xff0c;并导致频谱稀缺。超过数十亿的无线设备将被连接起来&#xff0c;并需要互联网接入。因此&#xff0c;无线电频谱管理方案的效率不足以授予对所有设备的访问权限。在频谱分配中&am…...

认识柔性数组

在C99中&#xff0c;结构中的最后一个元素允许是未知大小的数组&#xff0c;这就叫做柔性数组成员 限制条件是&#xff1a; 结构体中最后一个成员未知大小的数组 1.柔性数组的形式 那么我们怎样写一个柔性数组呢 typedef struct st_type {int i;int a[0];//柔性数组成员 }ty…...

熔断、限流、降级 —— SpringCloud Alibaba Sentinel

Sentinel 简介 Sentinel 是阿里中间件团队开源的&#xff0c;面向分布式服务架构的高可用流量防护组件&#xff0c;主要以流量为切入点&#xff0c;从限流、流量整形、熔断降级、系统负载保护、热点防护等多个维度来帮助开发者保障微服务的稳定性 Sentinel 提供了两个服务组件…...

树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频

使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...

在Ubuntu中设置开机自动运行(sudo)指令的指南

在Ubuntu系统中&#xff0c;有时需要在系统启动时自动执行某些命令&#xff0c;特别是需要 sudo权限的指令。为了实现这一功能&#xff0c;可以使用多种方法&#xff0c;包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法&#xff0c;并提供…...

PL0语法,分析器实现!

简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...

视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)

前言&#xff1a; 最近在做行为检测相关的模型&#xff0c;用的是时空图卷积网络&#xff08;STGCN&#xff09;&#xff0c;但原有kinetic-400数据集数据质量较低&#xff0c;需要进行细粒度的标注&#xff0c;同时粗略搜了下已有开源工具基本都集中于图像分割这块&#xff0c…...

回溯算法学习

一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)

本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...

Java数值运算常见陷阱与规避方法

整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...

4. TypeScript 类型推断与类型组合

一、类型推断 (一) 什么是类型推断 TypeScript 的类型推断会根据变量、函数返回值、对象和数组的赋值和使用方式&#xff0c;自动确定它们的类型。 这一特性减少了显式类型注解的需要&#xff0c;在保持类型安全的同时简化了代码。通过分析上下文和初始值&#xff0c;TypeSc…...

深入理解Optional:处理空指针异常

1. 使用Optional处理可能为空的集合 在Java开发中&#xff0c;集合判空是一个常见但容易出错的场景。传统方式虽然可行&#xff0c;但存在一些潜在问题&#xff1a; // 传统判空方式 if (!CollectionUtils.isEmpty(userInfoList)) {for (UserInfo userInfo : userInfoList) {…...

基于江科大stm32屏幕驱动,实现OLED多级菜单(动画效果),结构体链表实现(独创源码)

引言 在嵌入式系统中&#xff0c;用户界面的设计往往直接影响到用户体验。本文将以STM32微控制器和OLED显示屏为例&#xff0c;介绍如何实现一个多级菜单系统。该系统支持用户通过按键导航菜单&#xff0c;执行相应操作&#xff0c;并提供平滑的滚动动画效果。 本文设计了一个…...