首页 文章

为什么我在ASP .NET Excel Interop中出现内存不足错误?

提问于
浏览
2

这工作......我把处理代码移到了finally块,现在每次都失败了 .

我有一个测试电子表格,有4条记录,长6列 . 这是我用来引入它的代码 . 这是IIS 5(我的电脑)和IIS 6(Web服务器)上的ASP .Net 3.5 .

它在捕获之前的线上爆炸:“values =(object [,])range.Value2;”出现以下错误:

11/2/2009 8:47:43 AM :: Not enough storage is available to complete this operation. (Exception from HRESULT: 0x8007000E (E_OUTOFMEMORY))

有任何想法吗?建议?我从codeproject中获取了大部分代码,所以我不知道这是否是使用Excel的正确方法 . 感谢您的任何帮助,您可以提供 .

这是我的代码:

Excel.ApplicationClass app = null;
Excel.Workbook book = null;
Excel.Worksheet sheet = null;
Excel.Range range = null;

object[,] values = null;

try
{
    // Configure Excel
    app = new Excel.ApplicationClass();
    app.Visible = false;
    app.ScreenUpdating = false;
    app.DisplayAlerts = false;

    // Open a new instance of excel with the uploaded file
    book = app.Workbooks.Open(path);

    // Get first worksheet in book
    sheet = (Excel.Worksheet)book.Worksheets[1];

    // Start with first cell on second row
    range = sheet.get_Range("A2", Missing.Value);

    // Get all cells to the right
    range = range.get_End(Excel.XlDirection.xlToRight);

    // Get all cells downwards
    range = range.get_End(Excel.XlDirection.xlDown);

    // Get address of bottom rightmost cell
    string downAddress = range.get_Address(false, false, Excel.XlReferenceStyle.xlA1, Type.Missing, Type.Missing);

    // Get complete range of data
    range = sheet.get_Range("A2", downAddress);

    // get 2d array of all data
    values = (object[,])range.Value2;
}
catch (Exception e)
{
    LoggingService.log(e.Message);
}
finally
{
    // Clean up
    range = null;
    sheet = null;

    if (book != null)
        book.Close(false, Missing.Value, Missing.Value);

    book = null;

    if (app != null)
        app.Quit();

    app = null;
}

return values;

4 回答

  • 5

    我不确定这是不是你的问题,但很可能是 . 您没有正确清理excel对象 . 它们是非托管代码,清理起来可能很棘手 . 最后应该看起来像这样:并且评论已经注意到使用asp.net的excel并不是一个好主意 . 此清理代码来自winform应用程序:

    GC.Collect();
     GC.WaitForPendingFinalizers();
    
    
     System.Runtime.InteropServices.Marshal.FinalReleaseComObject(range);
     System.Runtime.InteropServices.Marshal.FinalReleaseComObject(sheet);
     System.Runtime.InteropServices.Marshal.FinalReleaseComObject(book);
    
     WB.Close(false, Type.Missing, Type.Missing);
    
     Excel.Quit();
     System.Runtime.InteropServices.Marshal.FinalReleaseComObject(Excel);
    

    EDIT

    另一种方法是使用ado.net打开工作簿 .

    DataTable dt = new DataTable();
    
                string connectionString;
                System.Data.OleDb.OleDbConnection excelConnection;
                System.Data.OleDb.OleDbDataAdapter da;
                DataTable dbSchema;
                string firstSheetName;
                string strSQL;
    
                connectionString = @"provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + filename + @";Extended Properties=""Excel 12.0;HDR=YES;IMEX=1""";
                excelConnection = new System.Data.OleDb.OleDbConnection(connectionString);
                excelConnection.Open();
                dbSchema = excelConnection.GetOleDbSchemaTable(System.Data.OleDb.OleDbSchemaGuid.Tables, null);
                firstSheetName = dbSchema.Rows[0]["TABLE_NAME"].ToString();
                strSQL = "SELECT * FROM [" + firstSheetName + "]";
                da = new OleDbDataAdapter(strSQL, excelConnection);
                da.Fill(dt);
    
                da.Dispose();
                excelConnection.Close();
                excelConnection.Dispose();
    
  • 0

    在每个请求上创建/销毁excel对于你所做的事情都将具有绝对可怕的性能 . 通常,使用自动化运行任何Office应用程序都是一项令人讨厌的业务,原因很多(参见here) . 我让它工作的唯一方法是有一个应用程序的单个实例(在我的情况下是Word)初始化一次,然后请求排队到这个实例进行处理

    如果你可以远离应用程序并自己解析文件(使用MS库,只需XML)

  • 1

    使用ASP.NET中的interop会遇到很多麻烦 . 除非这是针对一些微小的内部应用,否则建议不要继续使用它 .

    Office Interop不是传统意义上的编程API - 它是Office宏系统的最大化,具有处理进程间的能力 - 例如Excel宏可以与Outlook交互 .

    使用互操作的一些后果是:

    • 您实际上是在打开办公室应用程序的完整副本 .

    • 应用程序正在执行您的操作,就像用户启动它们一样 - 这意味着代替在代码中返回的错误消息,它们将显示在GUI中 .

    • 只有在您明确命令时才会关闭应用程序的副本 - 即使这样,错误也可能阻止实际发生(如果您没有可编程地告诉Excel不需要保存更改,则应用程序可能会显示"do you want to save"对话框) . 这通常会导致许多隐藏的Excel副本在系统上运行 - 打开任务管理器并查看正在运行的excel.exe进程数 .

    所有这些都使得互操作可以避免常规桌面应用程序,并且应该仅用作服务器应用程序的最后手段,因为需要操作或脚本泄漏进程的GUI弹出窗口是服务器环境中的谋杀 .

    一些替代品包括:

    • 使用基于Microsoft Office 2007 XML的格式,以便您可以自己编写XML文件 .

    • 使用SpreadsheetGear.Net,这是一个.NET二进制Excel文件读取器/写入器(您不需要安装Excel,因为它完全独立) . 在Intertop接口之后,SpreadsheetGear会自行建模,以便更容易地转换旧代码 .

  • 1

    错误可能正是它所说的,你得到的内存不足错误 . 尝试将values数组的加载拆分为几个较小的块,而不是一次获取整个Range . 我在C#中尝试了你的代码并且没有任何问题,但我加载的电子表格大多是空的 .

    我注意到Range虽然是整个电子表格(从A2到IV65536或其他东西) . 我不确定这是不是故意的 .

    您可以尝试使用的一件事是sheet.UsedRange,它将减少您正在加载的单元格数量 .

    我学到的其他一些小东西你可能会觉得有用:

    • 使用Application而不是ApplicationClass

    • 使用Marshal.FinalReleaseComObject(范围)(以及工作表,书籍,应用程序),否则您将有EXCEL.EXE过程 .

相关问题