Java 兼容读取WPS和Office图片,结合EasyExcel读取单元格信息
在Java开发中,处理Excel文件中的图片(包括浮动图片和嵌入图片)是一个常见的需求。本文将介绍如何使用EasyExcel和Apache POI库来读取Excel文件中的图片,并将其与数据进行关联。
1. 引言
在许多应用场景中,Excel文件不仅包含数据,还可能嵌入了图片。为了有效地提取这些图片并与数据关联,我们需要使用合适的库和方法。本文将详细介绍如何实现这一过程。
浮动图片

内嵌图片

pom
<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.3.2</version>
</dependency>
<dependency><groupId>org.jdom</groupId><artifactId>jdom2</artifactId><version>2.0.6</version>
</dependency>
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.9</version>
</dependency>
java代码
public class MySAXParserHandler extends DefaultHandler {String value = null;List<String> rows = new ArrayList<>();int rowIndex = 0;public List<String> getRows() {return rows;}/*** 用来标识解析开始*/@Overridepublic void startDocument() throws SAXException {// TODO Auto-generated method stubsuper.startDocument();// System.out.println("SAX解析开始");}/*** 用来标识解析结束*/@Overridepublic void endDocument() throws SAXException {// TODO Auto-generated method stubsuper.endDocument();// System.out.println("SAX解析结束");}/*** 解析xml元素*/@Overridepublic void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {// 调用DefaultHandler类的startElement方法super.startElement(uri, localName, qName, attributes);if (qName.equals("row")) {value = "";}}@Overridepublic void endElement(String uri, String localName, String qName)throws SAXException {//调用DefaultHandler类的endElement方法super.endElement(uri, localName, qName);if (qName.equals("row")) {if (value != null && value.contains("DISPIMG")) {value = value.substring(value.lastIndexOf("DISPIMG(")).replace("DISPIMG(\"", "");value = value.substring(0, value.indexOf("\""));rows.add(rowIndex, value);} else {rows.add(rowIndex, null);}rowIndex++;value = "";}}@Overridepublic void characters(char[] ch, int start, int length)throws SAXException {super.characters(ch, start, length);value += new String(ch, start, length);}
}
@Data
public class BatchSupplierGoodImportForm {private Integer supplierId;private String supplierCode;@Data@NoArgsConstructor@AllArgsConstructorpublic static class GoodItem {@ExcelProperty(value = "产品名称")private String productName;@ExcelImageProperty(value = {"imageUrl"}, index = 2)@ExcelProperty(value = "图片", converter = ExcelUrlImageConverter.class)private String imageUrl;@ExcelProperty(value = "品牌")private String supplierBrand;@ExcelProperty(value = "规格")private String skuDesc;@ExcelProperty(value = "集采价")private String groupPurchasePrice;@ExcelProperty(value = "卖点")private String sellPoint;}
}
public class ExcelImageExtractor2 {public static void main(String[] args) throws Exception {// 测试文件路径File xlsFile = new File("E:\\WeChat Files\\xxx\\FileStorage\\File\\2025-01\\测试.xls");File xlsxFile = new File("E:\\WeChat Files\\xxx\\FileStorage\\File\\2025-01\\测试.xlsx");String fileDir = "E:\\WeChat Files\\xxx\\FileStorage\\File\\2025-01";// 读取 .xls 文件中的浮动图片System.out.println("读取 .xls 文件中的浮动图片...");//readXlsImages(xlsFile, fileDir);// 读取 .xlsx 文件中的浮动图片System.out.println("读取 .xlsx 文件中的浮动图片...");//readXlsxImages(xlsxFile, fileDir);// 读取 .xlsx 文件中的嵌入图片System.out.println("读取 .xlsx 文件中的嵌入图片...");//readXlsxEmbeddedImages2(xlsxFile, fileDir);System.out.println("读取 ");importExcelSpuItem(xlsxFile, fileDir);}@SneakyThrowspublic static void importExcelSpuItem(File originalFile, String fileDir) {try {// 将上传的文件缓存到内存中,方便多次读取byte[] fileBytes = FileUtils.readFileToByteArray(originalFile);// 第一步:动态读取 Excel 文件的表头和所有数据List<Map<Integer, String>> headerList = new ArrayList<>();List<Map<Integer, String>> rawDataList = new ArrayList<>();List<BatchSupplierGoodImportForm.GoodItem> goodItemExcelInputs = new ArrayList<>();EasyExcel.read(new ByteArrayInputStream(fileBytes)).registerReadListener(new AnalysisEventListener<Map<Integer, String>>() {@Overridepublic void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {headerList.add(headMap); // 捕获表头信息}@Overridepublic void invoke(Map<Integer, String> data, AnalysisContext context) {// 检查是否为空行if (isEmptyRow(data)) {return; // 跳过空行}rawDataList.add(data); // 捕获每行数据}@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {// 不需要额外操作}}).sheet().doRead();// 检查是否成功读取到表头if (headerList.isEmpty()) {throw new RuntimeException("Excel 文件中没有表头");}// 第二步:读取 Excel 文件中的图片Map<Integer, String> imagePathMap = new HashMap<>(); // 行号 -> 图片路径readXlsxImages(originalFile, fileDir, imagePathMap);readXlsxEmbeddedImages2(originalFile, fileDir, imagePathMap);// 第三步:将图片与每行数据对应for (int i = 0; i < rawDataList.size(); i++) {Map<Integer, String> rowData = rawDataList.get(i);BatchSupplierGoodImportForm.GoodItem item = new BatchSupplierGoodImportForm.GoodItem();// 提取每列数据item.setProductName(rowData.get(0));item.setImageUrl(imagePathMap.getOrDefault(i + 1, null)); // 根据行号获取图片路径item.setSupplierBrand(rowData.get(2));item.setSkuDesc(rowData.get(3));item.setGroupPurchasePrice(rowData.get(4));item.setSellPoint(rowData.get(5));// 添加到列表goodItemExcelInputs.add(item);// 输出每行数据的文本内容和图片路径//System.out.println("行号: " + i);//System.out.println("数据: " + rowData);//System.out.println("图片路径: " + imagePathMap.getOrDefault(i, "无图片"));}System.out.println(goodItemExcelInputs);} catch (IOException e) {throw new RuntimeException("文件读取失败", e);}}/*** 判断是否为空行*/private static boolean isEmptyRow(Map<Integer, String> data) {for (String value : data.values()) {if (StringUtils.isNotBlank(value)) {return false;}}return true;}// 读取 .xls 文件中的浮动图片public static void readXlsImages(File file, String fileDir) throws Exception {HSSFWorkbook workbook = new HSSFWorkbook(new FileInputStream(file));for (Sheet sheet : workbook) {HSSFSheet hssSheet = (HSSFSheet) sheet;HSSFPatriarch drawingPatriarch = hssSheet.getDrawingPatriarch();if (drawingPatriarch != null) {List<HSSFShape> shapes = drawingPatriarch.getChildren();for (HSSFShape shape : shapes) {if (shape instanceof HSSFPicture) {HSSFPicture pic = (HSSFPicture) shape;HSSFPictureData picData = pic.getPictureData();HSSFClientAnchor anchor = (HSSFClientAnchor) shape.getAnchor();String key = anchor.getRow1() + "行," + anchor.getCol1() + "列";byte[] data = picData.getData();String suffix = picData.suggestFileExtension();File dir = new File(fileDir);if (!dir.exists()) dir.mkdirs();FileUtils.writeByteArrayToFile(new File(dir, key + "." + suffix), data);}}}}workbook.close();}// 读取 .xlsx 文件中的浮动图片public static void readXlsxImages(File file, String fileDir, Map<Integer, String> imagePathMap) throws Exception {XSSFWorkbook workbook = new XSSFWorkbook(new FileInputStream(file));for (Sheet sheet : workbook) {XSSFSheet xssSheet = (XSSFSheet) sheet;XSSFDrawing drawing = xssSheet.getDrawingPatriarch();if (drawing != null) {List<XSSFShape> shapes = drawing.getShapes();for (XSSFShape shape : shapes) {if (shape instanceof XSSFPicture) {XSSFPicture pic = (XSSFPicture) shape;XSSFPictureData picData = pic.getPictureData();XSSFClientAnchor anchor = (XSSFClientAnchor) shape.getAnchor();String key = anchor.getRow1() + "行," + anchor.getCol1() + "列";byte[] data = picData.getData();String suffix = picData.suggestFileExtension();File dir = new File(fileDir);if (!dir.exists()) dir.mkdirs();FileUtils.writeByteArrayToFile(new File(dir, key + "." + suffix), data);imagePathMap.put(anchor.getRow1(), key + "." + suffix);}}}}workbook.close();}// 读取 .xlsx 文件中的嵌入图片public static void readXlsxEmbeddedImages2(File file, String fileDir, Map<Integer, String> imagePathMap) throws Exception {OPCPackage opcPackage = OPCPackage.open(new FileInputStream(file));List<PackagePart> parts = opcPackage.getParts();Map<Integer, List<PackagePart>> picturePath = getEmbedPictures(parts);for (Integer sheetIndex : picturePath.keySet()) {List<PackagePart> rows = picturePath.get(sheetIndex);for (int i = 0; i < rows.size(); i++) {PackagePart part = rows.get(i);if (part != null) {InputStream imgIs = part.getInputStream();String name = part.getPartName().getName();// 从 XML 文件中解析行和列信息String cellPosition = getCellPosition(sheetIndex, i, parts);// 保存图片到本地File dir = new File(fileDir);if (!dir.exists()) dir.mkdirs();FileUtils.copyInputStreamToFile(imgIs, new File(dir, "工作表" + sheetIndex + "_" + cellPosition + "_" + name.substring(name.lastIndexOf("/") + 1)));imagePathMap.put(i, cellPosition + "_" + name.substring(name.lastIndexOf("/") + 1));}}}opcPackage.close();}/*** 获取图片所在的单元格位置(行和列)。** @param sheetIndex 工作表索引* @param imageIndex 图片索引* @param parts 压缩包中的所有部分* @return 单元格位置(如 "5行_3列")*/private static String getCellPosition(int sheetIndex, int imageIndex, List<PackagePart> parts) throws Exception {// 解析 `/xl/worksheets/sheet*.xml` 文件,获取行和列信息for (PackagePart part : parts) {String name = part.getPartName().getName();if (name.equals("/xl/worksheets/sheet" + (sheetIndex + 1) + ".xml")) {SAXParserFactory factory = SAXParserFactory.newInstance();SAXParser parser = factory.newSAXParser();MySAXParserHandler handler = new MySAXParserHandler();parser.parse(part.getInputStream(), handler);// 获取图片对应的行和列信息List<String> rows = handler.getRows();if (imageIndex < rows.size()) {return rows.get(imageIndex); // 返回行和列信息}}}return "未知行_未知列"; // 如果未找到,返回默认值}@SneakyThrowsprivate static Map<Integer, List<PackagePart>> getEmbedPictures(List<PackagePart> parts) {Map<String, Set<String>> mapImg = new HashMap<>();Map<String, String> mapImgPath = new HashMap<>();Map<Integer, List<String>> dataMap = new HashMap<>();for (PackagePart part : parts) {
// System.out.println(part.getPartName());PackagePartName partName = part.getPartName();String name = partName.getName();if ("/xl/cellimages.xml".equals(name)) {SAXBuilder builder = new SAXBuilder();// 获取文档Document doc = builder.build(part.getInputStream());// 获取根节点Element root = doc.getRootElement();List<Element> cellImageList = root.getChildren();for (Element imgEle : cellImageList) {Element xdrPic = imgEle.getChildren().get(0);Element xdrNvPicPr = xdrPic.getChildren().get(0);Element xdrBlipFill = xdrPic.getChildren().get(1);Element aBlip = xdrBlipFill.getChildren().get(0);Attribute attr = aBlip.getAttributes().get(0);String imgId = xdrNvPicPr.getChildren().get(0).getAttributeValue("name");String id = attr.getValue();
// if (id.equals("rId12")) {
// System.out.println(attr.getValue() + "\t" + imgId);
// }if (mapImg.containsKey(id)) {mapImg.get(id).add(imgId);} else {Set<String> set = new HashSet<>();set.add(imgId);mapImg.put(id, set);}}}if ("/xl/_rels/cellimages.xml.rels".equals(name)) {SAXBuilder builder = new SAXBuilder();// 获取文档Document doc = builder.build(part.getInputStream());// 获取根节点Element root = doc.getRootElement();List<Element> relationshipList = root.getChildren();/*<Relationship Id="rId999" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="media/image1000.jpeg"/>*/for (Element relationship : relationshipList) {String id = relationship.getAttributeValue("Id");String target = relationship.getAttributeValue("Target");mapImgPath.put(id, target);
// if (id.equals("rId12")) {
// System.out.println(id + "\t" + target);
// }}}if (name.contains("/xl/worksheets/sheet")) {
// SAXBuilder builder = new SAXBuilder();// 获取文档String sheetNoStr = name.replace("/xl/worksheets/sheet", "").replace(".xml", "");Integer sheetNo = Integer.valueOf(sheetNoStr) - 1;// 步骤1:创建SAXParserFactory实例SAXParserFactory factory = SAXParserFactory.newInstance();// 步骤2:创建SAXParser实例SAXParser parser = factory.newSAXParser();MySAXParserHandler handler = new MySAXParserHandler();parser.parse(part.getInputStream(), handler);List<String> rows = handler.getRows();dataMap.put(sheetNo, rows);}}// for (Integer sheetNo : dataMap.keySet()) {
// System.out.println(sheetNo + "\t" + dataMap.get(sheetNo).size());
// }Map<String, String> imgMap = new HashMap<>();for (String id : mapImg.keySet()) {Set<String> imgIds = mapImg.get(id);String path = mapImgPath.get(id);for (String imgId : imgIds) {imgMap.put(imgId, path);}}for (Integer key : dataMap.keySet()) {List<String> rows = dataMap.get(key);for (int i = 0; i < rows.size(); i++) {String imgId = rows.get(i);if (imgMap.containsKey(imgId)) {rows.set(i, imgMap.get(imgId));}}}Map<Integer, List<PackagePart>> map = new HashMap<>();for (Integer key : dataMap.keySet()) {List<PackagePart> list = new ArrayList<>();map.put(key, list);List<String> pathList = dataMap.get(key);for (int i = 0; i < pathList.size(); i++) {list.add(i, null);String path = pathList.get(i);if (StringUtils.isNotEmpty(path)) {for (PackagePart part : parts) {PackagePartName partName = part.getPartName();String name = partName.getName();// /xl/media/image373.jpeg = media/image702.jpegif (name.contains(path)) {list.set(i, part);break;}}}}}return map;}
}
参考链接:https://blog.csdn.net/qq_23123177/article/details/133638391
相关文章:
Java 兼容读取WPS和Office图片,结合EasyExcel读取单元格信息
在Java开发中,处理Excel文件中的图片(包括浮动图片和嵌入图片)是一个常见的需求。本文将介绍如何使用EasyExcel和Apache POI库来读取Excel文件中的图片,并将其与数据进行关联。 1. 引言 在许多应用场景中,Excel文件不…...
电脑硬盘系统迁移及问题处理
一、系统迁移准备 1、确认你的电脑主板是否支持安装两块硬盘,如电脑主板有多个M2硬盘接口,我们将新硬盘安装到主板上,原来的老硬盘安装在第二个接口上,主板只有一个M2接口的话可以使用移动硬盘盒。 2、新硬盘安装好后,我们进入原来的系统,在 此电脑–右键–管理–磁盘管…...
网关 + Nacos配置管理
网关 网关:就是网络的关口,负责请求的路由、转发、身份校验。 网关路由 新建网关模块gateway引入相关依赖 <!--网关--> <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter…...
《Spring Framework实战》6:核心技术 4.1.IoC 容器
欢迎观看《Spring Framework实战》视频教程 本章介绍 Spring 的控制反转 (IoC) 容器。 本部分摘要 Spring IoC 容器和 Bean 简介 容器概述 Bean 概述 依赖 Bean 作用域 自定义 Bean 的性质 Bean 定义继承 容器扩展点 基于注解的容器配置 Clas…...
ModuleNotFoundError: No module named ‘audioop‘
问题 ModuleNotFoundError: No module named pyaudioop ModuleNotFoundError: No module named audioop解决方案 安装库 pip3 install audioop-lts...
STM32-笔记38-I2C-oled实验
一、什么是I2C? I2C总线,全称Inter-Integrated Circuit(互连集成电路),是一种由Philips(现NXP半导体)公司在1980年代初开发的同步 串行 半双工通信总线。 二、有了串口通信为什么要使用I2C&…...
人大金仓实现主键自增.
使用数据库中自带的参数类型 serial 类型(相当于创建一个INT列), 或者bigserial(相当于创建一个BIGINT列. 示例sql: CREATE TABLE ord(id SERIAL,ord_no INT NOT NULL,ord_name VARCHAR(32),CONSTRAINT "ord_PKEY" PRIMARY KEY ("id"));插入时指定自增值…...
h264之多视点mvc编码及解码过程(JMVC平台举例)
h264标准参考平台JMVC是针对MVC标准的,JMVC支持多视点编码、合流、多视点解码操作。可以利用JMVC生成h264 mvc码流和解码。 JMVC的下载地址是:jvet / JMVC GitLabH.264/AVC multi-view coding (MVC) extension JMVC reference softwarehttps://vcgit.hh…...
小程序学习08—— 系统参数获取和navBar组件样式动态设置
一 系统信息的概念 uni-app提供了异步(uni.getSystemInfo)和同步(uni.getSystemInfoSync)的2个API获取系统信息。 success 返回参数说明: 参数分类说明statusBarHeight手机状态栏的高度system操作系统名称及版本。。。 二 自定义navbar 2.1 获取系统参数 代码展示…...
数据库环境安装(day1)
网址:MySQL 下载(环境准备): (2-5点击此处,然后选择合适的版本) 1.linux在线YUM仓库 下载/安装: wget https://repo.mysql.com//mysql84-community-release-el9-1.noarch.rpm rpm -i https://r…...
网络安全-web渗透环境搭建-BWAPP(基础篇)
01--所需系统环境: 虚拟主机系统部署(vmware,虚拟主机创建、虚拟主机网络配置(桥接,便于网络中多个主机都能访问虚拟主机)、虚拟软件功能,快照、克隆、镜像文件加载,ova文件制作&am…...
当算法遇到线性代数(三):实对称矩阵
实对称矩阵的理论与应用 线性代数系列相关文章(置顶) 1.当算法遇到线性代数(一):二次型和矩阵正定的意义 2.当算法遇到线性代数(二):矩阵特征值的意义 3.当算法遇到线性代数&#x…...
WayLand的架构和协议
WayLand的架构和协议 1. Wayland简介 1.1 Wayland是啥?为啥它这么重要? 嘿,你知道吗?有时候咱们用电脑的时候,是不是觉得图形界面有点慢、有点卡?那是因为我们还在用一个叫X Window System (X11)的老伙计…...
STM32学习(十)
I2C模块内部结构 I2C(Inter-Integrated Circuit)模块是一种由Philips公司开发的二线式串行总线协议,用于短距离通信,允许多个设备共享相同的总线。 硬件连接简单:I2C通信仅需要两条总线,即SCL&…...
进阶篇-Day17:JAVA的日志、枚举、类加载器、反射等介绍】
目录 1、日志1.1 日志概念1.2 日志框架(1) Logback框架:(2)配置文件介绍: 2、枚举3、类加载器3.1 类加载器的介绍3.2 类加载器的加载过程:加载、链接、初始化3.3 类加载器的分类3.4 双亲委派模式…...
Java设计模式 —— 【行为型模式】责任链模式(Chain-of-responsibility Pattern) 详解
文章目录 模式介绍优缺点适用场景模式结构案例实现 模式介绍 责任链模式又名职责链模式,它是一种对象行为的设计模式,为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链&…...
C++和Python中负数取余结果的区别
C中的负数取余规则(取模%)规则 在C中,取余运算( % )的结果符号与被除数相同。从数学定义角度看,C遵循的是尽量让商向零取整的规则。例如计算 -7/3,商是 -2 (向零取整)&a…...
rust学习——环境搭建
rust安装:https://kaisery.github.io/trpl-zh-cn/ch01-01-installation.html 1、vscode装插件: toml语法支持 依赖管理 rust语法支持 2、创建demo 3、查看目录 4、执行文件的几种方式: rust安装:https://www.rust-lang.org/z…...
Linux系统中解决端口占用问题
在日常的 Linux 系统管理和开发过程中,端口占用是一个常见且令人头疼的问题。无论是部署新服务、调试应用程序,还是进行系统维护,遇到端口被占用都可能导致服务无法正常启动或运行。本文将详细介绍在 Linux 系统中如何识别和解决端口占用问题…...
现代软件架构设计:14个质量属性的定义、权衡与最佳实践
1. 引言 1.1 技术架构的重要性 技术架构是指导软件系统设计和开发的核心,它定义了系统的高层结构及关键技术选型。一个优秀的技术架构可以提高开发效率、系统稳定性和扩展能力,确保项目成功落地。面对复杂业务场景,技术架构的设计至关重要&…...
python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...
css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...
智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...
为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...
Leetcode 3577. Count the Number of Computer Unlocking Permutations
Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接:3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯,要想要能够将所有的电脑解锁&#x…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
#Uniapp篇:chrome调试unapp适配
chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器:Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...
Java数值运算常见陷阱与规避方法
整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...
