programing

NPOI 워크북 이후 MemoryStream이 닫혀 있는 것 같습니다.글?

showcode 2023. 5. 25. 22:11
반응형

NPOI 워크북 이후 MemoryStream이 닫혀 있는 것 같습니다.글?

ASP.NET 웹 API 프로젝트에서 데이터 테이블을 Excel로 변환하기 위해 NPOI를 사용하고 있습니다.

하지만 저는 응답에서 아무것도 얻지 못했습니다.내 코드는 다음과 같습니다.

public HttpResponseMessage GetExcelFromDataTable(DataTable dt)
{
    IWorkbook workbook = new XSSFWorkbook(); // create *.xlsx file, use HSSFWorkbook() for creating *.xls file.
    ISheet sheet1 = workbook.CreateSheet();
    IRow row1 = sheet1.CreateRow(0);
    for (int i = 0; dt.Columns.Count > i; i++)
    {
        row1.CreateCell(i).SetCellValue(dt.Columns[i].ColumnName);
    }

    for (int i = 0; dt.Rows.Count > i; i++)
    {
        IRow row = sheet1.CreateRow(i + 1);
        for (int j = 0; dt.Columns.Count > j; j++)
        {
            row.CreateCell(j).SetCellValue(dt.Rows[i][j].ToString());
        }
    }

    MemoryStream ms = new MemoryStream();
    workbook.Write(ms);
    HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
    result.Content = new StreamContent(ms);
    result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
    result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
    result.Content.Headers.ContentDisposition.FileName = string.Format("{0}.xlsx", dt.TableName);
    return result;
}

나는 브레이크 포인트를 설정하여 검사합니다.ms.Length끝나고workbook.Write(ms)그러나 예외를 반환합니다.System.ObjectDisposedException.

어디서부터 제가 잘못했을까요?

2020년 1월 3일 업데이트: Florian Dendorfer가 지적했듯이 2018년 10월에 스트림이 닫히지 않도록 오버라이드가 추가되었습니다.이 해결 방법을 사용하기 전에 오버로드를 먼저 시도하십시오(그리고 Florian의 답변에 투표하십시오!).

역사적인 목적을 위해 원래의 답을 남깁니다.


이 문제에 대한 또 다른 해결 방법은...다중을 사용하지 않는 것.MemoryStream물건들.

작성NpoiMemoryStream상속하는 클래스MemoryStream그리고 그것을 무시합니다.Close방법:

public class NpoiMemoryStream : MemoryStream
{
    public NpoiMemoryStream()
    {
        // We always want to close streams by default to
        // force the developer to make the conscious decision
        // to disable it.  Then, they're more apt to remember
        // to re-enable it.  The last thing you want is to
        // enable memory leaks by default.  ;-)
        AllowClose = true;
    }

    public bool AllowClose { get; set; }

    public override void Close()
    {
        if (AllowClose)
            base.Close();
    }
}

그런 다음 해당 스트림을 다음과 같이 사용합니다.

var ms = new NpoiMemoryStream();
ms.AllowClose = false;
workbook.Write(ms);
ms.Flush();
ms.Seek(0, SeekOrigin.Begin);
ms.AllowClose = true;

플러시와 시크 사이의 어느 지점에서 NPOI는 스트림을 닫으려고 시도하지만, 오버로드가 발생한 이후로Close()그리고AllowClose플래그는 거짓입니다. 스트림을 열어둘 수 있습니다.그러면, 세트AllowClose정상적인 폐기 메커니즘이 닫힐 수 있도록 실제 상태로 돌아갑니다.

오해하지 마...이건 아직 실행할 필요가 없는 해킹입니다하지만 메모리 사용의 관점에서 보면 좀 더 깨끗합니다.

이게 아직도 필요한지는 모르겠지만, 뭔가가 있습니다.overload

Write(Stream stream, bool leaveOpen)

설정한 경우 위치leaveOpen = trueMemoryStream을 열어 둡니다.

에서 설명한 것처럼, 그리고 이 질문에서도 스트림을 다른 MemoryStream에 공급할 수 있습니다.

...
MemoryStream ms = new MemoryStream();
using(MemoryStream tempStream = new MemoryStream)
{
    workbook.Write(tempStream);
    var byteArray = tempStream.ToArray();
    ms.Write(byteArray, 0, byteArray.Length);
    HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
    result.Content = new StreamContent(ms);
    result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
    result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
    result.Content.Headers.ContentDisposition.FileName = string.Format("{0}.xlsx", dt.TableName);
    return result;
}

이것을 해야만 하는 것에서 약간의 코드 냄새가 납니다.그러나 관련 타사 라이브러리가 스트림을 처리하는 방식 때문에 .xlsx 파일을 출력할 때만 필요합니다.

소유하지 않은 스트림을 닫거나 처리하는 API와 유사한 문제에 직면한 적이 있습니다.저는 NPOI에 대해 잘 모르지만, Write 메서드는 MemoryStream이 아닌 Stream을 수락하는 것이라고 생각합니다.그런 경우 모든 호출(읽기/쓰기/검색 등)을 내부 스트림(이 경우 MemoryStream)으로 전달하지만 닫기/폐기로 전달하지 않는 래퍼 스트림 클래스를 만들 수 있습니다.Wrapper를 Write 메서드로 전달합니다. 그러면 MemoryStream이 모든 내용을 포함하고 "열린" 상태여야 합니다.

또한, 당신은 아마도 필요할 필요가 있을 것입니다.ms.Seek(0, SeekOrigin.Begin)Write your memory stream(메모리 스트림 쓰기) 호출 후 스트림 끝에 위치하므로 해당 위치에서 읽으려고 하면 비어 있는 것으로 나타납니다.

언급URL : https://stackoverflow.com/questions/22931582/memorystream-seems-be-closed-after-npoi-workbook-write

반응형