使用 Apache POI 写入 excel。 FileNotFoundException:(请求的操作不能在用户映射部分打开的文件上执行)

Posted

技术标签:

【中文标题】使用 Apache POI 写入 excel。 FileNotFoundException:(请求的操作不能在用户映射部分打开的文件上执行)【英文标题】:Write to excel using Apache POI. FileNotFoundException:(The requested operation cannot be performed on a file with a user-mapped section open) 【发布时间】:2018-09-22 22:21:08 【问题描述】:

任何人都可以帮助阐明这一点吗?我正在尝试将一组数据写入到硒测试脚本中的下一个空行。我的代码用于在第一次执行时生成 excel,正确写入数据,但在第二次执行时(在同一个应用程序运行中),后续执行会抛出以下内容:

java.io.FileNotFoundException: TestResultData2.xls (The requested operation cannot be performed on a file with a user-mapped section open)

经过几个小时的尝试和搜索,我发现这可能与 Windows 问题有关(请参阅:https://bz.apache.org/bugzilla/show_bug.cgi?id=58480)但我不确定我是否遗漏了一些补救措施。大多数其他搜索表明这可能是由于不关闭 FileOutputStream 但它让我在那里感到困惑。 请参阅以下 exportDataToExcel 方法。请注意,我尝试了许多不同的方法,但这是我最近/测试次数最多的尝试。

public static void exportDataToExcel(String fileName, String tabName, String[][] data) throws FileNotFoundException, IOException, EncryptedDocumentException, InvalidFormatException, Exception
  
    //Create new workbook and tab
    Workbook wb;
    File newFile = new File(fileName);
    Sheet sheet = null;

    if (newFile.exists())  
           // Load existing
           wb = WorkbookFactory.create(newFile);
    else 
           if (newFile.getName().endsWith(".xls")) 
               wb = new HSSFWorkbook();
           else 
               throw new IllegalArgumentException("Unknown file type. Please use .xls");
           
    
    FileOutputStream fileOut = new FileOutputStream(newFile);

    // Check if the workbook is empty or not
    if (wb.getNumberOfSheets() != 0) 
        for (int i = 0; i < wb.getNumberOfSheets(); i++) 
           if (wb.getSheetName(i).equals(tabName)) 
               sheet = wb.getSheet(tabName);
           else sheet = wb.createSheet(tabName);
        
    else 
        // Create new sheet to the workbook if empty
        sheet = wb.createSheet(tabName);
    

      //Create 2D Cell Array
      Row[] row = new Row[data.length];
      Cell[][] cell = new Cell[row.length][];
      //Define and Assign Cell Data from Given
      for(int i = 0; i < row.length; i ++)
                 
          row[i] = sheet.createRow(i);  
          cell[i] = new Cell[data[i].length];

          for(int j = 0; j < cell[i].length; j ++)
          
              cell[i][j] = row[i].createCell(j);
              cell[i][j].setCellValue(data[i][j]);
          
      

      //Export Data
      wb.write(fileOut);
      fileOut.close();
      wb.close();
      System.out.println("File exported successfully");

  

我通过以下方式调用该方法:

String data[][]= cpAppFN, cpAppLN, cpAppDOB, cpAppSSN;
exportDataToExcel("TestResultData2.xls", "Results2", data);

下面的 Stacktrace,供参考。

Test_ConsumerPortal Line 210 is FileOutputStream fileOut = new FileOutputStream(newFile);Line 142 is exportDataToExcel("TestResultData2.xls", "Results2", data); 在测试本身内。

java.io.FileNotFoundException: TestResultData2.xls (The requested operation cannot be performed on a file with a user-mapped section open)
at java.io.FileOutputStream.open0(Native Method)
at java.io.FileOutputStream.open(Unknown Source)
at java.io.FileOutputStream.<init>(Unknown Source)
at java.io.FileOutputStream.<init>(Unknown Source)
at tests.Test_ConsumerPortal.exportDataToExcel(Test_ConsumerPortal.java:210)
at tests.Test_ConsumerPortal.Execution(Test_ConsumerPortal.java:142)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:124)
at org.testng.internal.Invoker.invokeMethod(Invoker.java:580)
at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:716)
at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:988)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:125)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:109)
at org.testng.TestRunner.privateRun(TestRunner.java:648)
at org.testng.TestRunner.run(TestRunner.java:505)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:455)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:450)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:415)
at org.testng.SuiteRunner.run(SuiteRunner.java:364)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:84)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1208)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1137)
at org.testng.TestNG.runSuites(TestNG.java:1049)
at org.testng.TestNG.run(TestNG.java:1017)
at org.testng.remote.AbstractRemoteTestNG.run(AbstractRemoteTestNG.java:114)
at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:251)
at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:77)


java.io.FileNotFoundException: TestResultData2.xls (The requested operation cannot be performed on a file with a user-mapped section open)
at java.io.FileOutputStream.open0(Native Method)
at java.io.FileOutputStream.open(Unknown Source)
at java.io.FileOutputStream.<init>(Unknown Source)
at java.io.FileOutputStream.<init>(Unknown Source)
at tests.Test_ConsumerPortal.exportDataToExcel(Test_ConsumerPortal.java:210)
at tests.Test_ConsumerPortal.Execution(Test_ConsumerPortal.java:142)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:124)
at org.testng.internal.Invoker.invokeMethod(Invoker.java:580)
at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:716)
at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:988)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:125)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:109)
at org.testng.TestRunner.privateRun(TestRunner.java:648)
at org.testng.TestRunner.run(TestRunner.java:505)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:455)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:450)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:415)
at org.testng.SuiteRunner.run(SuiteRunner.java:364)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:84)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1208)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1137)
at org.testng.TestNG.runSuites(TestNG.java:1049)
at org.testng.TestNG.run(TestNG.java:1017)
at org.testng.remote.AbstractRemoteTestNG.run(AbstractRemoteTestNG.java:114)
at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:251)
at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:77)

如果需要任何其他信息,请告诉我。

【问题讨论】:

【参考方案1】:

当调用wb = WorkbookFactory.create(newFile) 时,会在内部创建一个FileInputStream。在不关闭FileInputStream 的情况下,您正在调用FileOutputStream 中的FileOutputStream fileOut = new FileOutputStream(newFile);

当您创建工作簿时,WorkbookFactory.create(newFile)` 不会发挥作用,因此第一次尝试通过。在随后的尝试中,提到的代码路径被命中并且代码中断。

解决方案是如果文件存在则打开FileInputStream,然后将其传递给create()。完成更新 Excel 表中的值后,关闭 FileInputStream 并打开 FileOutputStream 以写入新数据。

下面的代码应该可以正常工作。

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;

public class ExcelDataUpdater 

    public static void exportDataToExcel(String fileName, String tabName, String[][] data)
            throws FileNotFoundException, IOException, EncryptedDocumentException, InvalidFormatException, Exception 
        // Create new workbook and tab
        FileInputStream inputStream = null;
        Workbook wb;
        Sheet sheet = null;

        // Check the file extension
        if (!fileName.endsWith(".xls")) 
            throw new IllegalArgumentException("Unknown file type. Please use .xls");
        

        File newFile = new File(fileName);

        // If file not exists we create a new workbook
        if (!newFile.exists()) 
            wb = new HSSFWorkbook();
         else 
            // If file exists, we open an input stream channel to it
            inputStream = new FileInputStream(newFile);
            // Provide the input stream to WorkbookFactory
            wb = WorkbookFactory.create(inputStream);
        

        // Check if the workbook is empty or not
        boolean isSheetFound = false;
        for (int i = 0; i < wb.getNumberOfSheets(); i++) 
            if (wb.getSheetName(i).equals(tabName)) 
                sheet = wb.getSheet(tabName);
                isSheetFound = true;
            
        
        if (!isSheetFound) 
            sheet = wb.createSheet(tabName);
        

        // Create 2D Cell Array
        Row[] row = new Row[data.length];
        Cell[][] cell = new Cell[row.length][];
        // Define and Assign Cell Data from Given
        for (int i = 0; i < row.length; i++) 
            row[i] = sheet.createRow(i);
            cell[i] = new Cell[data[i].length];

            for (int j = 0; j < cell[i].length; j++) 
                cell[i][j] = row[i].createCell(j);
                cell[i][j].setCellValue(data[i][j]);
            
        

        // If file already exists, we had opened an input stream.
        // We will close this here
        if (inputStream != null)
            inputStream.close();

        FileOutputStream outputStream = new FileOutputStream(newFile);

        // Export Data
        wb.write(outputStream);
        outputStream.close();
        wb.close();
        System.out.println("File exported successfully");
    

    public static void main(String[] args)
            throws InvalidFormatException, EncryptedDocumentException, FileNotFoundException, IOException, Exception 
        String data1[][] =   "A", "B", "C", "D"  ;
        ExcelDataUpdater.exportDataToExcel("TestResultData2.xls", "Results1", data1);

        String data2[][] =   "X", "Y", "Z", "W"  ;
        ExcelDataUpdater.exportDataToExcel("TestResultData2.xls", "Results2", data2);
    

我还优化了检查工作表是否存在和创建工作表的代码。

【讨论】:

这修复了错误。感谢您对我不知道的输入流的亲切解释,并清理了工作表检查。可能应该是一个单独的问题,但对于将来看到这一点并想知道为什么它仍可能替换同一行而不是添加到新行的任何人,只需将 row[i] = sheet.createRow(i); 替换为 int rowCount = sheet.getLastRowNum(); row[i] = sheet.createRow(rowCount+1); 很高兴为您提供帮助

以上是关于使用 Apache POI 写入 excel。 FileNotFoundException:(请求的操作不能在用户映射部分打开的文件上执行)的主要内容,如果未能解决你的问题,请参考以下文章

POI向Excel中写入数据及追加数据

循环类成员并写入 Excel Apache POI

无法写入Excel文件(Apache POI)

EasyExcel与Apache Poi快速掌握

使用 Apache POI 写入 excel。 FileNotFoundException:(请求的操作不能在用户映射部分打开的文件上执行)

JAVA使用poi包,向Excel中写入批量数据