java.lang.OutOfMemoryError:Java堆空间-无法修复

时间:2019-07-09 22:16:39

标签: java excel out-of-memory

我有此代码,并且此错误不断出现。我只有一个excel,但是似乎没有任何作用,我已经尝试了很多在网上冲浪的选项,但是根据我想做的事情似乎没有任何作用。

我使用不同的情况来简化我的业务逻辑,并且我不会更改它,所以我不确定如何解决此问题。

private static final String nombreArchivo = "casoPrueba.xlsx";
private static final String rutaArchivo = "src\\test\\resources\\data\\" + nombreArchivo;


public static XSSFSheet SacaHojaSegunTipo(String tipo) throws IOException {
    FileInputStream fis = new FileInputStream(new File(rutaArchivo));
    workbook = new XSSFWorkbook(fis);
    XSSFSheet spreadsheet = workbook.getSheetAt(0);
    if (tipo .equals("Candidatos Minorista")) {
        spreadsheet  = workbook.getSheetAt(1);
    }else if(tipo.equals("Conversion Candidatos")){
        spreadsheet  = workbook.getSheetAt(2);
    }else if(tipo.equals("Cuentas")){
        spreadsheet  = workbook.getSheetAt(3);
    }else if(tipo.equals("Detalle Cuenta")){
        spreadsheet  = workbook.getSheetAt(4);
    }else if(tipo.equals("Historial de Cuentas")){
        spreadsheet  = workbook.getSheetAt(5);
    }else if(tipo.equals("Navegar Cuentas")){
        spreadsheet  = workbook.getSheetAt(6);
    }else if(tipo.equals("Validar Número Operación")){
        spreadsheet  = workbook.getSheetAt(7);
    }else if(tipo.equals("Validar Tipos de Productos")){
        spreadsheet  = workbook.getSheetAt(8);
    }else if(tipo.equals("Validar Referencia y Cód. Auto.")){
        spreadsheet  = workbook.getSheetAt(9);
    }
    return spreadsheet;
}

2 个答案:

答案 0 :(得分:0)

这样的事情(我试图尽可能少地更改您的代码,所以它并不完美)

private static final String nombreArchivo = "casoPrueba.xlsx";
private static final String rutaArchivo = "src\\test\\resources\\data\\" + nombreArchivo;

private static XSSFWorkbook workbook = null;

public static XSSFSheet SacaHojaSegunTipo(String tipo) throws IOException {
    if (workbook == null) {
        try (FileInputStream fis = new FileInputStream(new File(rutaArchivo))) {
            workbook = new XSSFWorkbook(fis);
        }
    }
    XSSFSheet spreadsheet = null;
    switch (tipo) {
    case "Candidatos Minorista":
        spreadsheet  = workbook.getSheetAt(1);          
        break;
    case "Conversion Candidatos":
        spreadsheet  = workbook.getSheetAt(2);          
        break;
    case "Cuentas":
        spreadsheet  = workbook.getSheetAt(3);          
        break;
    case "Detalle Cuenta":
        spreadsheet  = workbook.getSheetAt(4);          
        break;
    case "Historial de Cuentas":
        spreadsheet  = workbook.getSheetAt(5);          
        break;
    case "Navegar Cuentas":
        spreadsheet  = workbook.getSheetAt(6);          
        break;
    case "Validar Número Operación":
        spreadsheet  = workbook.getSheetAt(7);          
        break;
    case "Validar Tipos de Productos":
        spreadsheet  = workbook.getSheetAt(8);          
        break;
    case "Validar Referencia y Cód. Auto.":
        spreadsheet  = workbook.getSheetAt(9);          
        break;
    default:
        spreadsheet = workbook.getSheetAt(0);
    }
    return spreadsheet;
}

答案 1 :(得分:0)

首先,请简短一点:值得注意以下内容
https://poi.apache.org/apidocs/dev/org/apache/poi/xssf/usermodel/XSSFWorkbook.html#XSSFWorkbook-java.io.InputStream-

  

使用InputStream比使用File需要更多的内存,因此如果   文件可用,那么您应该做类似的事情

   OPCPackage pkg = OPCPackage.open(path);
   XSSFWorkbook wb = new XSSFWorkbook(pkg);
   // work with the wb object
   ......
   pkg.close(); // gracefully closes the underlying zip file

(尽管执行wb.close()也会关闭文件和流)。

现在,您的核心问题是,在不再需要工作表或工作簿之后,您需要释放资源,但是由于这些资源隐藏在方法内部,因此您目前无法这样做。

因此,完成操作后,您需要授予呼叫者访问权以将其关闭。这是一个优先事项,但是我个人更希望将电子表格封装到其自己的类中-毕竟,电子表格本身就是一个明确定义的对象!因此,这需要从static进行更改,所以类似:

public class RutaArchivo implements AutoCloseable {
    private static final String nombreArchivo = "casoPrueba.xlsx";
    private static final String rutaArchivo = "src\\test\\resources\\data\\" + nombreArchivo;

    public static final String CANDIDATOS_MINORISTA = "Candidatos Minorista";
    public static final String CONVERSION_CANDIDATOS = "Conversion Candidatos"
    public static final String CUENTAS = "Cuentas";

    private XSSFWorkbook workbook;

    public RutaArchivo() throws InvalidFormatException, IOException {
        workbook = new XSSFWorkbook(new File(rutaArchivo));
    }

    @Override
    public void close() throws Exception {
        if (workbook != null) {
            workbook.close();
            workbook = null;
        }
    }

    public XSSFSheet sacaHojaSegunTipo(String tipo) {
         if (workbook == null) {
             throw new IllegalStateException("It's closed");
         }
         XSSFSheet spreadsheet = workbook.getSheetAt(0);
         if (tipo .equals(CANDIDATOS_MINORISTA)) {
             spreadsheet  = workbook.getSheetAt(1);
         }else if(tipo.equals(CONVERSION_CANDIDATOS)){
             spreadsheet  = workbook.getSheetAt(2);
         }else if(tipo.equals(CUENTAS)){
              spreadsheet  = workbook.getSheetAt(3);
         // etc, etc
         }

         return spreadsheet;
    }
}

需要注意的几件事:

  • 如果我们希望调用者关闭文件,则应该明确让他们也采取一些措施来打开文件,否则,将其挂起很容易。在上面的示例中,这在创建对象时是隐式的-就像FileInputStream等标准Java类型一样。

  • 使RutaArchivo成为AutoCloseable意味着它可以在try-with-resources中使用,因此会自动关闭-例如:

    try (RutaArchivo rutaArchivo = new RutaArchivo()) {
        XSSFSheet cuentas = rutaArchivo.getSheet(RutaArchivo.CUENTAS);
    }
    
  • 在工作表名称中使用常量可以减少错误(例如,调用该方法时没有错别字)

  • 因为这是它自己的类,而不是static方法,所以编写单元测试时更容易替换或模拟。

无论如何,有一些想法-希望他们有所帮助。