我必须从包含大约40列的Excel文件中读取数据,然后使用列索引逐个读取它。即:
Cell cell = row.getCell(0);
if (!(cell == null || cell.getCellType() == Cell.CELL_TYPE_BLANK)) {
cell.setCellType(Cell.CELL_TYPE_STRING);
// set in setter
}
但是这种方法与Excel文件的结构紧密结合,因为如果在它们之间添加任何新列,那么将需要主要代码(列的索引值)。
请建议我从Excel文件中读取数据的任何有效方法,应该与Excel的结构松散地结合,或者如果有任何其他方式可以提供列与Java对象字段的绑定。
答案 0 :(得分:1)
我建议相应地添加带有列信息(即名称)和进程列(即将它们映射到java对象)的标题行。可能你甚至可以使用反射API来反序列化对象。这样的东西用于将java对象保存到数据库,我不是很好,但你可以google并检查。
该标题行可以隐藏在XL中。
或者你可以在你的java代码中放置映射信息(不修改原始的XL文件) - 只需为它定义一个数据结构而不是row.getCell(0)
中的硬编码常量 - 它应该被改为解释你的meta-有关XL文件中列的数据。
换句话说,您将根据您正在处理的每个XL文件拥有数据定义,并根据该定义处理XL文件的通用代码。你应该有一个例程,将XL文件名和定义文件作为参数。
答案 1 :(得分:1)
创建了将从Excel读取每一行并为每行创建自定义java对象的实用程序。确保在使用前阅读底部的限制。
ExcelUtils.java:
import java.io.File;
import java.io.FileInputStream;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
public class ExcelUtils {
public static <T> List<T> read(String filePath,Class<T> objClass, Map<String,String> headersToPropertyMap){
try {
FileInputStream file = new FileInputStream(new File(filePath));
//Create Workbook instance holding reference to .xlsx file
XSSFWorkbook workbook = new XSSFWorkbook(file);
XSSFSheet sheet = workbook.getSheetAt(0);
Iterator<Row> rowIterator = sheet.iterator();
List<T> retList = new LinkedList<T>();
Constructor<T> constructor =objClass.getConstructor();
Map<Integer,String> columnIndexToProperty = null;
if(rowIterator.hasNext()){
Row row = rowIterator.next();
columnIndexToProperty = getCorrespondingColumnIndex(headersToPropertyMap,row);
}
while (rowIterator.hasNext())
{
T obj = constructor.newInstance();
Row row = rowIterator.next();
setObjectFromRow(obj,row,columnIndexToProperty);
retList.add(obj);
}
file.close();
return retList;
} catch (Exception e) {
e.printStackTrace();
}
return new LinkedList<T>();
}
private static <T> void setObjectFromRow(T obj, Row row, Map<Integer,String> columnIndexToProperty){
int numColumns = row.getPhysicalNumberOfCells();
for(int i=0;i<numColumns;i++){
Object value = getCellValue(row.getCell(i));
ReflectUtils.set(obj, columnIndexToProperty.get(i), value);
}
}
private static Map<Integer,String> getCorrespondingColumnIndex(Map<String,String> headersToPropertyMap,Row row){
int numColumns = row.getPhysicalNumberOfCells();
Map<Integer,String> columnIndexToProperty = new HashMap<Integer,String>();
for(int i=0;i<numColumns;i++){
Cell cell =row.getCell(i);
String header = cell.getStringCellValue();
String property = headersToPropertyMap.get(header);
if(property==null)
System.out.println("Warning: not able to find property with header: "+header);
columnIndexToProperty.put(i, property);
}
return columnIndexToProperty;
}
private static Object getCellValue(Cell cell ){
switch (cell.getCellType())
{
case Cell.CELL_TYPE_NUMERIC:
return cell.getNumericCellValue();
case Cell.CELL_TYPE_STRING:
return cell.getStringCellValue();
case Cell.CELL_TYPE_BOOLEAN:
return cell.getBooleanCellValue();
}
return null;
}
}
ReflectUtils.java:
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import com.google.common.base.Optional;
public class ReflectUtils {
public static boolean set(Object object, String fieldName, Object fieldValue) {
if(fieldName==null)
return false;
Class<?> clazz = object.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
Type pt=null;
try{
pt = field.getGenericType();
}catch(Exception e){
e.printStackTrace();
}
if(pt!=null && pt.getTypeName().equals("com.google.common.base.Optional<java.lang.String>"))
field.set(object, Optional.fromNullable(fieldValue));
else if(pt!=null && pt.getTypeName().equals("java.lang.String"))
if(fieldValue instanceof Double)
field.set(object, String.valueOf(((Double)fieldValue).intValue()));
else
field.set(object, String.valueOf(fieldValue));
else if(pt!=null && (pt.getTypeName().equals("java.lang.Integer") || pt.getTypeName().equals("int")))
if(fieldValue instanceof Double)
field.set(object, ((Double) fieldValue).intValue());
else
field.set(object, Integer.parseInt(String.valueOf(fieldValue)));
else
field.set(object, fieldValue);
return true;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
return false;
}
}
用法:
Map<String,String> headersToPropertyMap = new HashMap<String,String>();
//The header column name in excel-First, the property you wish to assign the value-firstName
headersToPropertyMap.put("First", "firstName");
headersToPropertyMap.put("Last", "lastName");
headersToPropertyMap.put("Email", "email");
headersToPropertyMap.put("orgNodeId", "companyname");
headersToPropertyMap.put("Company Name", "companynameString");
headersToPropertyMap.put("EULA", "eula");
headersToPropertyMap.put("Email Notification", "emailNotification");
return ExcelUtils.read("path to excel file",CUSTOM.class,headersToPropertyMap);
限制:
答案 2 :(得分:0)
有两种选择:
POI提供了Sheet.getFirstRowNum()/ getLastRowNum(),以便能够从第一行到最后一行,以及Cell的Row.getFirstCellNum()/ getLastCellNum()。
请注意,如果未填充某些行,则仍可能遇到空行/单元格。
Sheet和Row都实现了Iterable接口,因此您可以执行类似
的操作for(Row row : sheet) {
for(Cell cell : row) {
...
允许遍历所有可用的行/单元而不会遇到任何空项。