使用TestNG@DataProvider从xlsx取数时路径正确却报FileNotFoundException异常
问题描述
我的Excel文件共有3个工作表,我尝试使用TestNG的@DataProvider注解读取文件中的数据,在getTestData()方法中传入目标工作表名称,通过FileInputStream读取文件路径,打印输出的文件路径完全正确,路径为:C:\Users\Gaurav Pratap Singh\eclipse-workspace\SampleTestFrameworkGPS\src\main\java\com\crm\qa\testData\FreeCRMTestData.xlsx。我曾怀疑问题出在目录名称中的空格,但同目录下的config.properties文件可以正常被读取,不存在该问题。相关实现代码如下:
package com.crm.qa.util; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import org.apache.poi.EncryptedDocumentException; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.usermodel.WorkbookFactory; import com.crm.qa.base.TestBase; public class TestUtil extends TestBase { public static String TESTDATA_SHEET_PATH = System.getProperty("user.dir") + "\\src\\main\\java\\com\\crm\\qa\\testData\\FreeCRMTestData.xlsx"; public static Workbook book; public static Sheet sheet; public static Object[][] getTestData(String sheetName){ FileInputStream fis = null; try { fis = new FileInputStream(new File(TESTDATA_SHEET_PATH)); // File Path printing perfectly System.out.println("Sheet path " + TESTDATA_SHEET_PATH); } catch (FileNotFoundException e1) { e1.printStackTrace(); } System.out.println("Sheet path " + TESTDATA_SHEET_PATH); try { book = WorkbookFactory.create(fis); } catch (EncryptedDocumentException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } sheet = book.getSheet(sheetName); Object[][] data = new Object[sheet.getLastRowNum()][sheet.getRow(0).getLastCellNum()]; for (int i = 0; i < sheet.getLastRowNum(); i++) { for (int k = 0; k < sheet.getRow(0).getLastCellNum(); k++) { data[i][k] = sheet.getRow(i + 1).getCell(k).toString(); } } return data; } }
排查修复方案
- 工作表名称匹配校验
传入的sheetName参数必须和Excel中实际的工作表名称完全一致,注意区分大小写、去除前后多余空格,这是最常见的出错原因。如果工作表不存在,book.getSheet(sheetName)会返回null,后续调用sheet相关方法就会抛出空指针异常,可以加非空判断提前抛出明确的错误提示。 - 空行空单元格兼容处理
原代码默认Excel第一行是表头且所有行、单元格都有值,实际使用中如果表头行为空、某行数据为空或者某个单元格为空,都会触发空指针异常。可以增加如下兼容逻辑:// 读取工作表后先判断是否为空 if(sheet == null) { throw new RuntimeException("未找到名称为" + sheetName + "的工作表"); } // 表头行判空 if(sheet.getRow(0) == null) { throw new RuntimeException("工作表" + sheetName + "表头行为空"); } int rowCount = sheet.getLastRowNum(); int cellCount = sheet.getRow(0).getLastCellNum(); Object[][] data = new Object[rowCount][cellCount]; // 循环读取时增加单元格判空 for (int i = 0; i < rowCount; i++) { for (int k = 0; k < cellCount; k++) { data[i][k] = sheet.getRow(i + 1).getCell(k) == null ? "" : sheet.getRow(i + 1).getCell(k).toString(); } } - 资源自动释放优化
原代码中FileInputStream和Workbook使用后没有主动关闭,容易造成文件占用锁,导致后续读取文件失败。建议使用try-with-resources语法自动释放资源,优化后的代码如下:public static Object[][] getTestData(String sheetName){ try (FileInputStream fis = new FileInputStream(new File(TESTDATA_SHEET_PATH)); Workbook book = WorkbookFactory.create(fis)) { Sheet sheet = book.getSheet(sheetName); if(sheet == null) { throw new RuntimeException("未找到名称为" + sheetName + "的工作表"); } if(sheet.getRow(0) == null) { throw new RuntimeException("工作表" + sheetName + "表头行为空"); } int rowCount = sheet.getLastRowNum(); int cellCount = sheet.getRow(0).getLastCellNum(); Object[][] data = new Object[rowCount][cellCount]; for (int i = 0; i < rowCount; i++) { for (int k = 0; k < cellCount; k++) { data[i][k] = sheet.getRow(i + 1).getCell(k) == null ? "" : sheet.getRow(i + 1).getCell(k).toString(); } } return data; } catch (FileNotFoundException e) { e.printStackTrace(); throw new RuntimeException("测试数据文件未找到", e); } catch (EncryptedDocumentException | IOException e) { e.printStackTrace(); throw new RuntimeException("测试数据文件读取失败", e); } } - POI依赖校验
确认项目中引入的Apache POI依赖版本统一,且支持你使用的Excel格式:如果是.xlsx格式,需要同时引入poi和poi-ooxml两个依赖,版本号必须一致,避免依赖冲突导致读取失败。
内容的提问来源于stack exchange,提问作者Gaurav
相关产品推荐
相关产品推荐

