Java 从Excel文件读取数据的更好方法

Java 从Excel文件读取数据的更好方法,java,excel,apache-poi,Java,Excel,Apache Poi,我必须从一个Excel文件中读取数据,该文件大约有40列,我正在使用列索引逐个读取数据。i、 e: Cell cell = row.getCell(0); if (!(cell == null || cell.getCellType() == Cell.CELL_TYPE_BLANK)) { cell.setCellType(Cell.CELL_TYPE_STRING); // set in setter } 但这种方法和Exce

我必须从一个Excel文件中读取数据,该文件大约有40列,我正在使用列索引逐个读取数据。i、 e:

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对象字段的绑定。

我建议添加带有列信息(即名称)的标题行和处理列(即将它们映射到Java对象)因此。也许您甚至可以使用反射API来反序列化对象。类似的东西是用来将java对象保存到数据库的,我在这里不擅长,但你可以用谷歌搜索并检查

该标题行可以隐藏在XL中

或者,您可以将映射信息放在java代码中(不修改原始XL文件)-只需为此定义一个数据结构,而不是像在
row.getCell(0)
中那样硬编码常量-它应该更改为解释有关XL文件中列的元数据


换句话说,每个正在处理的XL文件都有数据定义,并且每个定义都有一个处理XL文件的通用代码。您应该有一个以XL文件名和定义文件为参数的例程。

有两个选项:

  • 第一/最后
  • 迭代器
第一/最后 POI提供Sheet.getFirstRowNum()/getLastRowNum(),以便能够从第一行向上移动到最后一行,并为单元格提供行.getFirstCellNum()/getLastCellNum()

请注意,如果某些行/单元格未填充,则仍可能遇到空行/单元格

迭代器 Sheet和Row都实现了Iterable接口,因此您可以执行以下操作

for(Row row : sheet) {
     for(Cell cell : row) {
          ...

它允许遍历所有可用的行/单元格,而不会遇到任何空项。

创建了一个实用程序,该实用程序将从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;
    }
}
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;
    }
}
导入java.io.File;
导入java.io.FileInputStream;
导入java.lang.reflect.Constructor;
导入java.util.HashMap;
导入java.util.Iterator;
导入java.util.LinkedList;
导入java.util.List;
导入java.util.Map;
导入org.apache.poi.ss.usermodel.Cell;
导入org.apache.poi.ss.usermodel.Row;
导入org.apache.poi.xssf.usermodel.xssfheet;
导入org.apache.poi.xssf.usermodel.xssf工作簿;
公开课的优异成绩{
公共静态列表读取(字符串文件路径、类objClass、映射头TopPropertyMap){
试一试{
FileInputStream file=newfileinputstream(新文件(filePath));
//创建包含对.xlsx文件引用的工作簿实例
XSSF工作簿=新XSSF工作簿(文件);
XSSFSheet sheet=workbook.getSheetAt(0);
迭代器rowIterator=sheet.Iterator();
List retList=新建LinkedList();
Constructor=objClass.getConstructor();
Map columnIndexToProperty=null;
if(roweiterator.hasNext()){
行=行迭代器。下一步();
ColumnIndexTopProperty=getCorrespondingColumnIndex(标题属性映射,行);
}
while(roweiterator.hasNext())
{
T obj=constructor.newInstance();
行=行迭代器。下一步();
setObjectFromRow(对象、行、列索引属性);
retList.add(obj);
}
file.close();
返回列表;
}捕获(例外e){
e、 printStackTrace();
}
返回新的LinkedList();
}
私有静态void setObjectFromRow(T obj,Row Row,Map columnIndexToProperty){
int numColumns=row.getPhysicalNumberOfCells();

对于(int i=0;i您使用哪个excel库?如果使用APACHE POI,则可以使用
getPhysicalNumberOfRows()
检查列和行的边界,对于行的列
getPhysicalNumberOfCells()
BTW,getPhysicalNumberOfCells()不会告诉您列在一行中的实际位置,它只是计算填充了多少单元格,但其间可能存在间隙。
        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);