POI EXCEL 03 07 版本圖片讀取 和寫入 操作
<!-- maven poi 引用包-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.17</version>
</dependency>
package rainJob.com.exercise;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import org.junit.jupiter.api.Test;
import java.io.*;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* @auth xiaoyu
* @desciption 利用poi 讀取 寫出圖片操作。
* @Date 13:13 2018/5/25
*/
public class PoiExercise {
@Test
public void mergerData() throws IOException, InvalidFormatException {
//讀取文件地址
File file = new File("C:\\Users\\lenovo\\Desktop\\test.xls");
//最終返回值
LinkedList<LinkedHashMap<String, Object>> linkedHashMaps = new LinkedList<>();
//爲了給03版本賦值
InputStream inputStream = new FileInputStream(file);
Workbook workbook = null;
if (file.getName().matches(".xlsx")) {
//獲取工作簿
workbook = new XSSFWorkbook(file);
} else {
workbook = new HSSFWorkbook(inputStream);
}
//這裏可以寫成fori形式,因爲我是測試的demo 所以下標就爲0了
Sheet sheetAt = workbook.getSheetAt(0);
//一行可能有多組圖片。picture方法獲取指定行 列 和圖片二進制數組。
Map<Integer, Map<Integer, byte[]>> picture = picture(sheetAt);
//獲取文本行。我覺得就只是CellTypeEnum 枚舉裏的這些纔會讀到
int physicalNumberOfRows = sheetAt.getLastRowNum();
//記錄第一行爲表頭
LinkedList<String> fieldName = new LinkedList<>();
//獲取第一行信息
Row row1 = sheetAt.getRow(0);
int lastCellNum = row1.getPhysicalNumberOfCells();
for (int i = 0; i < lastCellNum; i++) {
fieldName.add(i, row1.getCell(i).getStringCellValue());
}
//從第二行開始,獲取信息
for (int i = 1; i <= physicalNumberOfRows; i++) {
Row row = sheetAt.getRow(i);
//只能獲取CellTypeEnum 枚舉裏的這些纔會讀到
int lastCell = row.getPhysicalNumberOfCells();
//記錄一行的value值
LinkedHashMap<String, Object> rowValue = new LinkedHashMap<>();
for (int j = 0; j < lastCell; j++) {
String name = fieldName.get(j);
Cell cell = row.getCell(j);
if (cell == null) continue;
//進行拿到結果值
Object cellValue = getObject(cell);
rowValue.put(name, cellValue);
}
linkedHashMaps.add(rowValue);
}
//爲了防止文本行沒有數據 光有圖片的情況
if (!picture.isEmpty()) {
picture.forEach((k, v) -> {
LinkedHashMap<String, Object> stringObjectLinkedHashMap = null;
//如果我這個行有文本對應就爲true 沒有就是false
boolean fal = false;
if ((k - 1) >= linkedHashMaps.size()) {
stringObjectLinkedHashMap = new LinkedHashMap<>();
} else {
fal = true;
stringObjectLinkedHashMap = linkedHashMaps.get(k - 1);
}
LinkedHashMap<String, Object> finalStringObjectLinkedHashMap = stringObjectLinkedHashMap;
if (!v.isEmpty()) {
v.forEach((key, val) -> {
String name = fieldName.get(key);
int cellLength = finalStringObjectLinkedHashMap.keySet().toArray().length;
//對應圖片的位置進行賦值。
if (key >= cellLength) {
for (int i = cellLength; i < key; i++) {
finalStringObjectLinkedHashMap.put(fieldName.get(i), null);
}
}
finalStringObjectLinkedHashMap.put(name, val);
});
if (fal) {
linkedHashMaps.remove(k - 1);
if ((k - 1) > linkedHashMaps.size()) {
linkedHashMaps.add(finalStringObjectLinkedHashMap);
} else linkedHashMaps.add((k - 1), finalStringObjectLinkedHashMap);
} else {
//如果不存在文本行直接後面追加。沒生成空行。也可以你們想生成就生成。
linkedHashMaps.add(finalStringObjectLinkedHashMap);
}
}
});
}
//進行寫出。爲了節省造數據格式問題。
writePicture(fieldName, linkedHashMaps);
}
/**
* 判斷cell的枚舉 並對應處理成一個Object對象
*
* @param cell
* @return
*/
private Object getObject(Cell cell) {
Object cellValue = null;
switch (cell.getCellTypeEnum()) {
case _NONE:
cellValue = null;
break;
case NUMERIC:
if (DateUtil.isCellDateFormatted(cell)) {
if (cell.getNumericCellValue() < 1) {
} else {
//判斷字段類型是時間還是日期
SimpleDateFormat sdf = null;
String dateValue = DateUtil.getJavaDate(cell.getNumericCellValue()).toString();
//判斷時間類型還是日期類型。
boolean matches = dateValue.matches(".*00:00:00.*");
if (matches) {
sdf = new SimpleDateFormat("yyyy-MM-dd");
} else {
sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}
cellValue = sdf.format(DateUtil.getJavaDate(cell.getNumericCellValue()));
}
} else {
//數字轉化
cellValue = String.valueOf(cell.getNumericCellValue());
cellValue = new BigDecimal(cellValue.toString());
BigDecimal bigDecimal = ((BigDecimal) cellValue).stripTrailingZeros();
cellValue = bigDecimal.toPlainString();
}
break;
case STRING:
cellValue = cell.getStringCellValue();
break;
case FORMULA:
break;
case BLANK:
break;
case BOOLEAN:
break;
case ERROR:
break;
}
return cellValue;
}
/**
* 讀取圖片幷包裝Map -->key 是rowIndex -->value
* 是map map-->key -->cellIndex value->byte[]圖片二進制數組
*
* @param sheet
* @return
*/
private Map<Integer, Map<Integer, byte[]>> picture(Sheet sheet) {
//map 返回值
Map<Integer, Map<Integer, byte[]>> map = new LinkedHashMap();
//sheet.getDrawingPatriarch() 返回工作表現有的圖形,如果還沒有,則返回null。
if (sheet.getDrawingPatriarch() != null) {
//甄別07
if (sheet instanceof XSSFSheet) {
XSSFSheet sheetTemp = (XSSFSheet) sheet;
//此形狀組中的形狀列表
for (XSSFShape shape : sheetTemp.getDrawingPatriarch().getShapes()) {
// 若果形狀組是圖片 還有自定義圖形的情況。
if (shape instanceof XSSFPicture) {
XSSFPicture picture = (XSSFPicture) shape;
// 獲取圖片的錨點
XSSFAnchor anchor = picture.getAnchor();
if (anchor instanceof XSSFClientAnchor) {
int row1 = ((XSSFClientAnchor) anchor).getRow1();
int cell1 = ((XSSFClientAnchor) anchor).getCol1();
setByte(map, row1, cell1, picture.getPictureData().getData());
map.put(row1, map.get(row1));
}
}
}
} else {
//甄別03
HSSFSheet sheetTemp = (HSSFSheet) sheet;
//sheet.getDrawingPatriarch() 獲取drawingPatriarch的區域。
Spliterator<HSSFShape> spliterator = sheetTemp.getDrawingPatriarch().spliterator();
spliterator.forEachRemaining(shape -> {
if (shape instanceof HSSFPicture) {
HSSFPicture picture = (HSSFPicture) shape;
HSSFAnchor anchor = picture.getAnchor();
if (anchor instanceof HSSFClientAnchor) {
int row1 = ((HSSFClientAnchor) anchor).getRow1();
int cell1 = ((HSSFClientAnchor) anchor).getCol1();
setByte(map, row1, cell1, picture.getPictureData().getData());
map.put(row1, map.get(row1));
}
}
});
}
}
return map;
}
/**
* 不管是03 還是07的通用方法,進行判斷是否存在那一行的那一列,進行添加數據
*
* @param map
* @param row1
* @param cell1
* @param data
*/
private void setByte(Map<Integer, Map<Integer, byte[]>> map, int row1, int cell1, byte[] data) {
if (!map.containsKey(row1)) {
Map<Integer, byte[]> map1 = new LinkedHashMap();
map1.put(cell1, data);
map.put(row1, map1);
} else {
Map<Integer, byte[]> integerMap = map.get(row1);
if (!integerMap.containsKey(cell1)) {
integerMap.put(cell1, data);
}
}
}
/**
* poi 寫出帶有圖片的工具類
* 只是07的03的就是改變下類就行。
*
* @param fieldNames
* @param values
* @throws InvalidFormatException
* @throws IOException
*/
public void writePicture(List<String> fieldNames, LinkedList<LinkedHashMap<String, Object>> values) throws InvalidFormatException, IOException {
XSSFWorkbook workbook = new XSSFWorkbook();
XSSFSheet sheet = workbook.createSheet();
XSSFDrawing xssfdrawing = sheet.createDrawingPatriarch();
XSSFRow rowOne = sheet.createRow(0);
for (int i = 0; i < fieldNames.size(); i++) {
XSSFCell cell = rowOne.createCell(i);
cell.setCellValue(fieldNames.get(i));
}
for (int i = 0; i < values.size(); i++) {
LinkedHashMap<String, Object> stringObjectLinkedHashMap = values.get(i);
XSSFRow row = sheet.createRow((i + 1));
Object[] keyArray = stringObjectLinkedHashMap.keySet().toArray();
for (int j = 0; j < keyArray.length; j++) {
Object cellValue = stringObjectLinkedHashMap.get(keyArray[j].toString());
if (cellValue instanceof byte[]) {
//這塊設置的時候一定要col2比col1大要不圖片不會出來
//dx1 dy1 dx2 dy2 可以隨意指定吧。。沒弄清楚含義
// XSSFClientAnchor xssfClientAnchor = new XSSFClientAnchor(0, 0, 0, 0, j, i + 1, j + 1, i + 2);
//一開始無參構造不行 最後行了。。
XSSFClientAnchor xssfClientAnchor = new XSSFClientAnchor();
xssfClientAnchor.setCol1(j);
xssfClientAnchor.setCol2(j + 1);
xssfClientAnchor.setRow1(i + 1);
xssfClientAnchor.setRow2(i + 2);
//插入圖片
xssfdrawing.createPicture(xssfClientAnchor, workbook.addPicture((byte[]) cellValue, XSSFWorkbook.PICTURE_TYPE_PNG));
} else {
XSSFCell cell = row.createCell(j);
if (cellValue != null) {
cell.setCellValue(cellValue.toString());
}
}
}
}
FileOutputStream fileOutputStream = new FileOutputStream("io.xlsx");
workbook.write(fileOutputStream);
workbook.close();
fileOutputStream.close();
}
}