ASP .NET Excel Interop을 수행할 때 메모리 부족 오류가 발생하는 이유는 무엇입니까?
-
12-09-2019 - |
문제
이것 ~였다 작업중입니다..그리고 폐기 코드를 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 프로세스가 계속 유지됩니다.