为什么我得到一个内存不足错误做ASP .NET Excel互操作?

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

我有一个testing电子表格,有4个logging,6列长。 这里是我使用它的代码。这是IIS 5(我的电脑)和IIS 6(Web服务器)上的ASP .Net 3.5。

它会在catch之前的下一行发生:“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))

有任何想法吗? build议? 我从代码项目中得到了大部分代码,所以我不知道这是否是使用Excel的正确方法。 感谢您的任何帮助,您可以提供。

这是我的代码:

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

 object [,] values = null;

尝试
 {
     //configurationExcel
     app = new Excel.ApplicationClass();
     app.Visible = false;
     app.ScreenUpdating = false;
     app.DisplayAlerts = false;

     //用上传的文件打开一个新的excel实例
     book = app.Workbooks.Open(path);

     //获取书中的第一张工作表
     sheet =(Excel.Worksheet)book.Worksheets [1];

     //从第二行的第一个单元格开始
    范围= sheet.get_Range(“A2”,Missing.Value);

     //获取所有单元格
     range = range.get_End(Excel.XlDirection.xlToRight);

     //获取所有单元格向下
     range = range.get_End(Excel.XlDirection.xlDown);

     //获取最右下angular的单元格的地址
     string downAddress = range.get_Address(false,false,Excel.XlReferenceStyle.xlA1,Type.Missing,Type.Missing);

     //获取完整的数据范围
     range = sheet.get_Range(“A2”,downAddress);

     //获取所有数据的2d数组
     values =(object [,])range.Value2;
 }
捕获(例外e)
 {
     LoggingService.log(e.Message);
 }
最后
 {
     // 清理
     range = null;
     sheet = null;

    如果(book!= null)
        closures(false,Missing.Value,Missing.Value);

     book = null;

    如果(app!= null)
         app.Quit();

     app = null;
 }

返回值;

我不确定这是不是你的问题,但很可能。 你没有正确地清理你的Excel对象。 他们是非托pipe的代码,可能会很棘手的清理。 最后应该看起来像这样:而且正如注释已经注意到从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); 

编辑

另一种方法是使用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(); 

创build/销毁Excel的每一个请求将有绝对可怕的performance,不pipe你做什么。 一般来说运行任何使用自动化的Office应用程序是一个令人讨厌的业务,原因很多(请看这里 )。 我得到它的唯一方法是有一个应用程序的单个实例(在我的情况下,Word)初始化一次,然后请求排队到这个实例进行处理

如果您可以远离应用程序并自行parsing文件(使用MS库,仅使用XML)

使用ASP.NET的interop会遇到很多麻烦。 除非这意味着一些小的内部应用程序,否则build议不要继续使用它。

Office Interop不是传统意义上的编程API,而是Officemacros系统,它具有处理进程的能力 – 例如,Excelmacros可以与Outlook进行交互。

使用interop的一些后果是:

  • 您实际上正在打开办公室应用程序的完整副本。
  • 您的操作正在由应用程序执行,就像用户启动它们一样 – 这意味着代替返回错误消息,它们将显示在GUI中。
  • 您的应用程序副本只有在您明确命令的情况下才会closures – 即使这样,错误也可以防止实际发生(如果您没有可编程地告诉Excel这些更改不需要,应用程序可能会显示“是否要保存”对话框被保存)。 这通常会导致许多隐藏的Excel副本在系统上运行 – 打开任务pipe理器并查看有多less个excel.exe进程正在运行。

所有这些使得互操作性避免了常规的桌面应用程序,以及只能作为服务器应用程序的最后手段的东西,因为需要操作或脚本泄露进程的GUIpopup窗口在服务器环境中是谋杀的。

一些替代品包括:

  • 使用基于Microsoft Office 2007 XML的格式,以便您可以自己编写XML文件。
  • 使用SpreadsheetGear.Net ,这是一个.NET二进制Excel文件读取器/写入器(不需要安装Excel,因为它是完全独立的)。 SpreadsheetGear在Intertop接口之后自行build模,使旧代码的转换更容易。

该错误可能正是它所说的,你正在得到一个内存不足的错误。 尝试将值数组的加载拆分成几个较小的块,而不是一次获取整个范围。 我在C#中试过你的代码,没有问题,但我加载的电子表格大多是空的。

我注意到范围是整个电子表格,但(从A2到IV65536什么的)。 我不确定这是否是有意的。

有一件事你可以尝试使用sheet.UsedRange,这将减less你正在加载的单元格的数量。

一些额外的小东西,我已经了解到你可能会觉得有用:

  • 使用Application而不是ApplicationClass
  • 使用Marshal.FinalReleaseComObject(范围)(也适用于工作表,书籍,应用程序),否则你会有你的EXCEL.EXE进程粘附。