ASP .NET Excel Interop을 수행할 때 메모리 부족 오류가 발생하는 이유는 무엇입니까?

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

문제

이것 ~였다 작업중입니다..그리고 폐기 코드를 finally 블록으로 옮겼는데 이제는 매번 실패합니다.

4개의 레코드, 6개의 열 길이로 구성된 테스트 스프레드시트가 있습니다.이를 가져오는 데 사용하는 코드는 다음과 같습니다.이는 IIS 5(내 PC) 및 IIS 6(웹 서버)의 ASP .Net 3.5입니다.

잡기 직전에 라인에서 폭발합니다."값 = (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;
도움이 되었습니까?

해결책

이것이 귀하의 문제인지 아닌지는 잘 모르겠지만 그럴 수도 있습니다.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);

편집하다

대안은 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)의 단일 인스턴스를 갖고 요청이 처리를 위해 이 인스턴스에 대기하는 것입니다.

앱을 사용하지 않고 직접 파일을 구문 분석할 수 있는 경우(단지 XML의 MS 라이브러리 사용)

ASP.NET의 상호 운용성을 사용하면 많은 문제에 직면하게 될 것입니다.이것이 소규모 내부 응용 프로그램을 위한 것이 아니라면 진행하지 않는 것이 좋습니다.

Office Interop은 전통적인 의미의 프로그래밍 API가 아닙니다. 이는 프로세스 간 작업 기능을 최대한 활용한 Office 매크로 시스템입니다. 예를 들어 Excel 매크로는 Outlook과 상호 작용할 수 있습니다.

Interop을 사용하면 다음과 같은 결과가 발생합니다.

  • 실제로는 Office 응용 프로그램의 전체 복사본을 여는 것입니다.
  • 귀하의 작업은 마치 사용자가 작업을 시작한 것처럼 애플리케이션에 의해 실행됩니다. 즉, 오류 메시지가 코드로 반환되는 대신 GUI에 표시됩니다.
  • 응용 프로그램 복사본은 명시적으로 명령한 경우에만 닫힙니다. 그런 경우에도 오류가 실제로 발생하는 것을 방지할 수 있습니다. 변경 사항이 필요하지 않다고 Excel에 프로그래밍 방식으로 알리지 않은 경우 응용 프로그램은 "저장하시겠습니까?" 대화 상자를 표시할 수 있습니다. 저장됩니다).이로 인해 일반적으로 시스템에 Excel의 숨겨진 복사본이 많이 실행되는 결과가 발생합니다. 작업 관리자를 열고 얼마나 많은 excel.exe 프로세스가 실행되고 있는지 확인하세요.

이 모든 것은 일반 데스크톱 응용 프로그램에서는 피해야 할 상호 운용성을 만들고 서버 응용 프로그램에서는 최후의 수단으로만 사용해야 하는 상호 운용성을 만듭니다. 프로세스를 유출하는 작업이나 스크립트가 필요한 GUI 팝업은 서버 환경에서 살인이기 때문입니다.

몇 가지 대안은 다음과 같습니다.

  • Microsoft Office 2007 XML 기반 형식을 사용하면 XML 파일을 직접 작성할 수 있습니다.
  • 사용 스프레드시트Gear.Net, .NET 바이너리 Excel 파일 판독기/작성기입니다(완전히 독립형이므로 Excel을 설치할 필요가 없습니다).SpreadsheetGear는 Intertop 인터페이스를 모델로 하여 이전 코드를 더 쉽게 변환할 수 있습니다.

오류는 아마도 정확히 말한 것과 같을 것입니다. 메모리 부족 오류가 발생하는 것입니다.전체 범위를 한 번에 가져오는 대신 값 배열 로드를 여러 개의 작은 청크로 분할해 보세요.C#에서 코드를 시험해 본 결과 아무런 문제가 없었지만 로드하던 스프레드시트가 대부분 비어 있었습니다.

나는 Range가 전체 스프레드시트(A2에서 IV65536까지)라는 것을 알았습니다.의도한 것인지 잘 모르겠습니다.

사용해 볼 수 있는 한 가지 방법은 로드 중인 셀 수를 줄이는 sheet.UsedRange입니다.

제가 배운 몇 가지 추가 소소한 내용은 여러분에게 유용할 것입니다.

  • ApplicationClass 대신 애플리케이션 사용
  • Marshal.FinalReleaseComObject(range)(시트, 책, 앱에도 적용)를 사용하세요. 그렇지 않으면 EXCEL.EXE 프로세스가 계속 유지됩니다.
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top