Почему я получаю сообщение об ошибке нехватки памяти при выполнении ASP.СЕТЕВОЕ взаимодействие с Excel?

StackOverflow https://stackoverflow.com/questions/1662982

Вопрос

Это был работает .. и я переместил код удаления в блок finally, и теперь он каждый раз дает сбой.

У меня есть тестовая таблица с 4 записями длиной в 6 столбцов.Вот код, который я использую для его ввода.Это ASP .Net 3.5 на IIS 5 (мой компьютер) и на IIS 6 (веб-сервер).

Он взрывается на леске прямо перед уловом:"значения = (object[,])диапазон.Значение2;" со следующей ошибкой:

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;
Это было полезно?

Решение

Я не уверен, ваша это проблема или нет, но вполне возможно.Вы неправильно очищаете свои объекты Excel.Это неуправляемый код, и его может быть сложно очистить.Наконец-то должно выглядеть что-то вроде этого:И, как отмечалось в комментариях, работать с Excel из asp.net - не очень хорошая идея.Этот код очистки взят из приложения 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();

Другие советы

Создание / уничтожение excel по каждому запросу будет иметь абсолютно ужасную производительность независимо от того, что вы делаете.В общем, запуск любого приложения Office с использованием автоматизации - неприятное занятие по многим причинам (см. здесь).Единственный способ заставить это работать - иметь один экземпляр приложения (в моем случае Word), который инициализируется один раз, а затем запросы ставятся в очередь к этому экземпляру для обработки

Если вы можете держаться подальше от приложений и самостоятельно проанализировать файл (используя библиотеки MS, только XML)

Вы столкнетесь с большими проблемами при использовании interop from ASP.NET.Если это не предназначено для какого-то крошечного внутреннего приложения, было бы желательно не использовать его дальше.

Office Interop - это не программный API в традиционном смысле этого слова - это макросистема Office, доведенная до максимума, с возможностью межпроцессной работы - например, макрос Excel может взаимодействовать с Outlook.

Некоторыми последствиями использования interop являются:

  • Фактически вы открываете полную копию приложения Office.
  • Ваши действия выполняются приложением так, как если бы их инициировал пользователь - это означает, что вместо сообщений об ошибках, возвращаемых в коде, они отображаются в графическом интерфейсе.
  • Ваша копия приложения закрывается только в том случае, если вы явно прикажете ей - и даже тогда ошибки могут помешать этому на самом деле произойти (приложение может отобразить диалоговое окно "хотите ли вы сохранить", если вы программно не сообщили Excel, что изменения сохранять не нужно).Обычно это приводит к тому, что в системе остается запущенным множество скрытых копий Excel - откройте диспетчер задач и посмотрите, сколько процессов запущено excel.exe.

Все это делает взаимодействие чем-то, чего следует избегать для обычного настольного приложения, и чем-то, что следует использовать только в качестве последнего средства для серверных приложений, поскольку всплывающее окно с графическим интерфейсом, требующее действия или скрипта, который пропускает процесс, является убийством в серверной среде.

Некоторые альтернативы включают:

  • Использование форматов на основе Microsoft Office 2007 XML, позволяющих вам самостоятельно создавать XML-файлы.
  • Используя SpreadsheetGear.Net, который представляет собой программу чтения / записи двоичных файлов Excel .NET (вам не нужен установленный Excel, так как он полностью автономен).SpreadsheetGear моделирует себя по образцу интерфейсов Intertop, чтобы упростить преобразование старого кода.

Вероятно, ошибка - это именно то, что там написано, вы получаете ошибку нехватки памяти.Попробуйте разделить загрузку массива значений на несколько меньших фрагментов вместо того, чтобы получать весь диапазон за один раз.Я попробовал ваш код на C #, и у меня не возникло проблем, но моя электронная таблица, которую я загружал, была в основном пустой.

Я заметил, что Диапазон был всей электронной таблицей (от A2 до IV65536 или что-то в этом роде).Я не уверен, что так было задумано.

Единственное, что вы могли бы попробовать использовать, - это sheet.Используйте Range, это сократит количество загружаемых вами ячеек.

Пара дополнительных мелочей, которые я узнал и которые могут оказаться полезными для вас:

  • Используйте Application вместо ApplicationClass
  • Используйте Marshal.FinalReleaseComObject(диапазон) (а также для листа, книги, приложения), в противном случае ваш EXCEL.EXE процесс застрянет.
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top