首先展示一下需要的效果:
在Excel内插入文件对象,其实就是关联到另一个文件,可以在这里点击图标直接打开文件进行编辑。
在Excel内操作的话是点击工具栏的插入--》附件--》对象/附件
首先了解好创建流程后其实我们在套用到代码里面就比较好理解了,我们这里是使用了POI包去操作Excel。
大概的步骤就是:
创建表格--》上传文件--》获取文件视图管理器(获取文件图标用)--》写入文件图标--》写入文件--》创建画布锚点坐标(就是文件放在哪里)--》最后将图标、文件、锚点设置进去--》最后输出
上代码
这里也借鉴了CSDN上面一些老哥的代码,我只是把我的理解更加详细的标注出来,为了给小白更好的理解很学习。
package com.gsr.Excel;
import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
import org.apache.poi.hssf.usermodel.HSSFObjectData;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.util.IOUtils;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.filechooser.FileSystemView;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
public class InsertTxtFileAsOleObject {
public static void main(String[] args) throws IOException {
//只有HSSFWorkbook才能使用OLE对象,并且poi需要在4.0之上
// 创建工作簿和工作表对象
Workbook workbook = new HSSFWorkbook ();
Sheet sheet = workbook.createSheet("Sheet1");
/** 这里是为了图标方便看,实际应用可以不管 */
sheet.setColumnWidth(0, 10000);//设置单元格的宽度
//设置单元格高度
Row row = sheet.createRow(0);
row.setHeightInPoints(1000);
// 读取需要添加的文件,如果有需要添加多个文件的需求,可以循环表格来添加
File pdfFile = new File("C:\\Users\\阿辉\\Desktop\\111.zip");
FileInputStream fis = new FileInputStream(pdfFile);
byte[] pdfBytes = new byte[(int) pdfFile.length()];
fis.read(pdfBytes);
fis.close();
/** 这一步是获取文件图标 */
// 获取文件系统视图
FileSystemView view = FileSystemView.getFileSystemView();
Icon systemIcon = view.getSystemIcon(pdfFile);
// 将 Icon 对象转换为 Image 对象
Image image = iconToImage(systemIcon);
// 将 Image 对象转换为字节数组
byte[] imageBytes = imageToByteArray(image);
/** 自定义文件的展示图标 */
// String imagePath = "C:\\Users\\阿辉\\Desktop\\Snipaste_2024-04-01_12-04-43.png"; // 图片文件路径 这个是excel中单元格中pdf文件对应展示出来的图片,可以自定义
// BufferedImage image = ImageIO.read(new File(imagePath));
// ByteArrayOutputStream baos = new ByteArrayOutputStream();
// ImageIO.write(image, "png", baos);
// byte[] imageBytes = baos.toByteArray();
// baos.close();
//将文件的图标添加进入到Excel文件内
int iconid = workbook.addPicture(imageBytes, HSSFWorkbook.PICTURE_TYPE_JPEG);
// 在工作表中创建OLE对象,就是将文件插入到Excel文件中
int pdfIdx = workbook.addOlePackage(pdfBytes, "222.zip", "333.zip", "111.zip");
/**
pdfBytes: 表示 PDF 文件的字节数组。您需要将 PDF 文件的内容以字节数组的形式传递给此参数。
"222.zip": 表示 OLE 对象的类型。如果导出之后,在excel中操作另存文件,这个名称就是新保存文件的默认名称【文件标签】
"333.zip": 这指定了要在OLE Package中使用的类名。在此示例中,你可以将其设置为任何你想要的类名,因为它不会对后续的操作产生影响。它也只是用于标识特定的OLE Package【文件名】。
"111.zip":这是在Excel工作簿中显示的OLE Package的名称,如果需要在excel中打开pdf文档,命名一定要以.pdf结尾,不然在excel中打不开!!!。
*/
// 创建画布和锚点
Drawing<?> drawing = sheet.createDrawingPatriarch();
ClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 1, 1, 0, 0);//这里的参数后续根据传过来的信息来变化。row,col
anchor.setAnchorType(HSSFClientAnchor.AnchorType.MOVE_AND_RESIZE);
//文件略缩图会占据整个单元格,锚点随单元格大小的改变而自动调整。这意味着当单元格的大小发生变化时,图片的大小也会相应地进行调整。
//在后续应用业务的时候,可以给单元格固定的高度和宽度,让略缩图更加美观
//参数1:起始列的偏移量(单位为字符宽度的 1/256)
//参数2:起始行的偏移量(单位为字符高度的 1/256)
//参数3:结束列的偏移量(单位为字符宽度的 1/256)
//参数4:结束行的偏移量(单位为字符高度的 1/256)
//参数5:起始列
//参数6:起始行
//参数7:结束列
//参数8:结束行
// 创建图片并将它关联到OLE对象
/**
* 这里参数是:
* 文件放在Excel表格内的位置:anchor
* 文件在Excel表格内的索引:pdfIdx(文件本身,文件能否打开的关键)
* 文件在Excel表格内的图标:iconid(文件的图标)
* */
drawing.createObjectData(anchor, pdfIdx, iconid);
//输出
try (OutputStream outputStream = new FileOutputStream("C:\\Users\\阿辉\\Desktop\\未命名1.xlsx")) {
workbook.write(outputStream);
System.out.println("文件写入成功!");
}
workbook.close();
}
// 将 Icon 对象转换为 Image 对象
private static Image iconToImage(Icon icon) {
if (icon instanceof ImageIcon) {
return ((ImageIcon) icon).getImage();
} else {
int width = icon.getIconWidth();
int height = icon.getIconHeight();
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics graphics = image.createGraphics();
icon.paintIcon(null, graphics, 0, 0);
graphics.dispose();
return image;
}
}
// 将 Image 对象转换为字节数组
private static byte[] imageToByteArray(Image image) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ImageIO.write(imageToBufferedImage(image), "png", byteArrayOutputStream);
return byteArrayOutputStream.toByteArray();
}
// 将 Image 对象转换为 BufferedImage 对象
private static BufferedImage imageToBufferedImage(Image image) {
if (image instanceof BufferedImage) {
return (BufferedImage) image;
}
BufferedImage bufferedImage = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics2D = bufferedImage.createGraphics();
graphics2D.drawImage(image, 0, 0, null);
graphics2D.dispose();
return bufferedImage;
}
}
这里单独解释一下设置文件的几个参数在哪里,不然小白会很懵逼。
另外画布锚点的设置和最后的保存锚点关系在代码注释里都标明了,可以封装成方法去调用。
上图补充一下,参数2的标签名字就是附在excel上面那个图标下面的名称
OLE:
OLE,全称Object Linking and Embedding,意为“对象链接和嵌入”,是一种实现应用程序间数据共享和交互的技术。通过OLE,用户可以在一个应用程序中使用另一个应用程序的功能和数据,而无需离开当前应用程序。
OLE不仅是桌面应用程序集成,而且还定义和实现了一种允许应用程序作为软件“对象”(数据集合和操作数据的函数)彼此进行“连接”的机制,这种连接机制和协议称为组件对象模型(COM)。OLE可以用来创建复合文档,这种文档包含了来自不同源应用程序的、具有不同类型的数据,因此它可以将文字、声音、图像、表格、应用程序等组合在一起。
另外HSSFWorkbook
类是 . xls
格式(Excel 97-2003版本)XSSFWorkbook
类是 .xlsx
格式(Excel 2007 及以后版本)
但是我这里输出是 .xlsx
格式格式,我使用XSSFWorkbook
类去创建工作表输出的时候并没有看到设置的文件。
然而!!!我用HSSFWorkbook
类去创建的时候居然成了,并且输出都没问题,不知道为啥,有知道的可以评论区踢一下。