Apache POI工作簿中的多线程



我想在多线程环境中写入HSSFWorkBook或XSSFWorkBook。每个线程将在相同或不同的表中进行修改。

try {
    String filePath="C:/Test.xlsx";
    FileInputStream fileInputStream = new FileInputStream(filePath);
    Workbook workbook = new XSSFWorkbook(fileInputStream);
    FileOutputStream fos = new FileOutputStream(filePath);
    workbook.write(fos);
    fos.close();
    fileInputStream.close();
} catch(Exception e) {
    e.printStackTrace();
    System.out.println(e.getMessage());
}

在SOAPUI中的LoadTest with MultiThreading中测试此代码时。我得到了一个例外:

Workbook workbook = new XSSFWorkbook(fileInputStream);

例外情况如下:

org.apache.poi.POIXMLException: org.apache.poi.openxml4j.exceptions.InvalidFormatException: Package should contain a content type part [M1.13]
请注意:Apache POI明确不支持对同一工作簿对象的多线程访问!这是因为有些结构是在工作簿级别上处理的,例如样式、注释。。。

如果你天真地尝试这样做,你会遇到晦涩难懂的错误和损坏的文档。

它所做的唯一保证是,不同线程中的单独工作簿将正常工作,即任何地方都不存在线程不安全的全局状态。

唯一可行的方法是通过同步块同步对工作簿的每次访问:

synchronized (workbook) {
    ... access the sheet and the contents
}

只读访问可能有效,但ApachePOI并不能保证对同一工作簿的并发读取访问有效。

更新:现在有一个相应的FAQ条目也说明了这一点。

通过读取文件C:/Test.xlsx创建XSSFWorkbook;被调用的构造函数是构造OPCPackageXSSFWorkbook(InputStream)。此C:/Test.xlsx文件必须有效,即未损坏,不为空。

如果要创建工作簿,则不应读取空文件,而应使用适当的构造函数。

关于多线程,我还没有测试过,但不同线程可以做什么是有限制的(例如,每个XSSheet一个)。看看这个邮件档案。

有解决方案。。。我在数组中创建行。。。我在线程中使用数组,Tu-debes-evitar使用在线程中创建行,因为这种方法是由线程安全的监控的

对不起,我不会说英语。。。我太努力了。

static int count=0;
  
    
    XSSFWorkbook workbook = new XSSFWorkbook();
    XSSFSheet sheet = workbook.createSheet("Products");
    sheet.createFreezePane(0, 1); // this will freeze first five rows
    
    int rowCount = 0;
    
    rowCount = getExcelTittle(sucsCompetencia,sucsProveedor, sucsPuntoVenta, sheet, rowCount);  

    // trucazo para multithread
    List<Row> r = new ArrayList<Row>();
    //List<Drawing> h = new ArrayList<Drawing>();
    
    //cell creation
    for ( int j = 0 ; j < ps.size() + 500 ; j++) {
        r.add(sheet.createRow(j));
        //h.add(sheet.createDrawingPatriarch());
    }
    // cells creation .. its a good idea do it 
    Map<String,Cell> cellMap = new HashMap<String,Cell>();
    for (int j = 0 ; j < r.size() ; j++) {
        for ( int  i = 0 ; i < 9 + sucsCompetencia.size() + sucsProveedor.size() + sucsPuntoVenta.size() ; i++) {
            cellMap.put( j + "-" + i, r.get(j).createCell(i));
        }

    }       
    
    Stream<Producto> arrStream = ps.parallelStream();
    arrStream.forEach(p->
                        {   
                            count++;
        int contadorPropio = count;
        
        if (contadorPropio % 1000 == 0)  log.info("* Procesando Generacion Excel " + contadorPropio + " de " + ps.size());
        
       // if (rowCount == 1000 ) break;
        
        
        int columnCount = 0;
        
        
        {
            //IMPORTANTEEEEEEEE
            Cell cell = cellMap.get(contadorPropio + "-" + columnCount++); 
            cell.setCellValue(p.getIdProducto());
        }     

在主线程内创建工作簿,工作簿创建工作表,并将工作表分发给工作线程。主线程应该等待,直到所有工作线程完成。主线程工作簿将数据刷新到流中。然后流式传输到文件中。

如果你想要带示例的源代码,请给我发邮件。我会分享ramesh.niwas@gmail.com

最新更新