0%

POI 读取 Excel 合并单元格内容:完整解决方案

在处理包含合并单元格的 Excel 时,直接读取非左上角的单元格会返回空值(因为合并单元格仅左上角单元格保存数据)。本文将详细讲解如何识别合并单元格、读取合并区域的内容,并提供通用工具类,确保在各种合并场景下准确获取数据。

合并单元格的特性与读取难点

合并单元格的存储规则

Excel 中合并单元格(如 CellRangeAddress 定义的区域)仅在左上角第一个单元格中存储数据,其他被合并的单元格均为空。例如:

  • 合并 A1:A3(3 行 1 列)后,仅 A1 有值,A2A3 为空;
  • 合并 B2:D4(3 行 3 列)后,仅 B2 有值,B3C2 等均为空。

直接读取的问题

若直接通过 row.getCell(column) 读取合并区域内的非左上角单元格,会返回 null 或空值,导致数据丢失。因此,需要:

  • 先判断单元格是否属于合并区域;
  • 若属于,则读取合并区域左上角单元格的值。

核心工具类实现

以下工具类提供合并单元格的判断、内容读取等功能,兼容 .xls.xlsx 格式。

阅读全文 »

POI读取excel报错解决方案:兼容 xls 与 xlsx 格式

在使用 POI 读取 Excel 文件时,因文件格式(.xls.xlsx)不同常出现格式不匹配的错误。本文将详细解析错误原因,提供通用解决方案,并介绍 WorkbookFactory 的使用技巧,帮助你无缝兼容两种格式。

错误原因分析

错误信息解读

当使用 POIFSFileSystem 读取 .xlsx 文件时,会出现以下错误:

1
The supplied data appears to be in the Office 2007+ XML. You are calling the part of POI that deals with OLE2 Office Documents. You need to call a different part of POI to process this data (eg XSSF instead of HSSF)  
  • 原因:
    • .xls(Excel 2003 及以前)基于 OLE2 格式,需用 HSSF 相关类(如 POIFSFileSystemHSSFWorkbook)处理;
    • .xlsx(Excel 2007 及以后)基于 XML 格式,需用 XSSF 相关类(如 XSSFWorkbook)处理。
    • 若用 HSSF 类读取 .xlsx 文件(或反之),会因格式不匹配报错。

常见错误用法

手动判断文件格式并选择对应类,容易因判断逻辑错误导致兼容问题:

阅读全文 »

spark性能优化全指南:从算法到资源的全方位调优

Spark 作为分布式计算引擎,其性能受算法设计、资源配置、数据分布等多因素影响。不合理的实现或配置可能导致任务运行缓慢、资源浪费甚至失败。本文从算法优化、并行度调整、缓存策略、内存管理、数据倾斜处理等维度,系统讲解 Spark 性能优化的核心方法,帮助开发者将任务效率提升数倍。

算法性能优化:选择高效的算子与数据处理方式

Spark 算子的选择直接影响任务的 Shuffle 数据量和计算复杂度,合理使用算子可减少不必要的开销。

避免低效算子,优先选择聚合类算子

低效算子 高效替代方案 优化原理
groupByKey reduceByKey / aggregateByKey groupByKey 仅分组不聚合,会将所有数据 Shuffle 到 Reduce 端;reduceByKey 在 Map 端先预聚合,减少 Shuffle 数据量
flatMap + groupByKey combineByKey combineByKey 支持自定义 Map 端聚合逻辑,灵活控制中间结果
cartesian(笛卡尔积) 避免使用,或通过过滤提前减少数据量 笛卡尔积会产生 N*M 条数据,极易导致 OOM,仅在小数据集场景使用

使用分区级算子减少任务启动开销

  • mapPartitions 替代 map
    map 对每条数据执行一次函数调用,mapPartitions 对每个分区执行一次函数调用(处理整个分区数据),减少函数初始化开销(如数据库连接创建)。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // 低效:每条数据创建一次连接  
    rdd.map(record => {
    val conn = getDBConnection() // 重复创建连接
    process(record, conn)
    })

    // 高效:每个分区创建一次连接
    rdd.mapPartitions(iterator => {
    val conn = getDBConnection() // 分区内共享连接
    iterator.map(record => process(record, conn))
    })
  • foreachPartition 替代 foreach:类似 mapPartitions,适合批量输出场景(如批量写入数据库)。

数据倾斜的算法级优化

数据倾斜(某 Key 对应数据量远超其他 Key)会导致单个 Task 耗时过长,可通过加盐散列分散倾斜 Key:

阅读全文 »

AES 对称加密算法详解

AES(Advanced Encryption Standard,高级加密标准)是目前应用最广泛的对称加密算法之一,作为 DES 的替代者,它具有更高的安全性和效率,被广泛用于金融、通信、数据存储等领域。

AES 的核心特性

  • 对称加密:加密和解密使用相同的密钥,这意味着通信双方需要共享同一个密钥。
  • 安全性高:相比 DES 算法,AES 的密钥长度更长(支持 128 位、192 位、256 位),抗暴力破解能力更强。
  • 效率优异:在硬件和软件环境中都能高效实现,适合处理大量数据的加密。
  • 应用广泛:是美国联邦政府采用的加密标准,也是众多行业的首选加密方案。

代码解析:AES 加密与解密过程

加密流程(aesEncode方法)

  1. 初始化随机数生成器

    1
    2
    SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
    random.setSeed("PASSWORD_CRYPT_KEY".getBytes());

    通过指定种子(这里使用 “PASSWORD_CRYPT_KEY”)确保密钥生成的一致性,相同的种子会生成相同的密钥。

  2. 生成密钥

阅读全文 »

消息摘要算法详解

消息摘要算法是密码学中的重要组成部分,主要用于验证数据的完整性,确保数据在传输或存储过程中未被篡改。这类算法通过对原始数据进行处理,生成一个固定长度的 “摘要”(也称为哈希值或散列值),该摘要具有唯一性和不可逆性,成为数据的 “数字指纹”。

消息摘要算法的核心特性

  • 单向性:从原始数据生成摘要很容易,但无法从摘要反推原始数据。
  • 唯一性:不同的原始数据几乎不可能生成相同的摘要(哈希碰撞概率极低)。
  • 固定长度:无论原始数据大小如何,生成的摘要长度固定。
  • 敏感性:原始数据的微小变化会导致摘要发生巨大改变。

三大系列消息摘要算法

MD 算法(Message Digest)

MD 算法是早期的消息摘要算法系列,由 Ronald L. Rivest 设计,主要代表为MD5

MD5 的特点
  • 生成128 位的信息摘要(二进制),转换为十六进制后为 32 位字符串。
  • 运算速度快,但安全性已被攻破(存在实际的碰撞案例)。
  • 目前更多用于非安全性要求极高的场景,如文件校验、数据一致性验证等。
MD5 的 Java 实现示例
阅读全文 »