es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Memoria del flujo Descartada después de utilizar el método Workbook.Save() OpenXML.

He estado lidiando con esto durante horas sin éxito. Estoy tratando de copiar un archivo de Excel, agregar una nueva hoja a él, poner el archivo en un MemoryStream y luego devolver el stream.

Aquí está el código:

public Stream ProcessDocument()
{
        var resultStream = new MemoryStream();

    string sourcePath = "path\\to\\file";
    string destinationPath = "path\\to\\file";

    CopyFile(destinationPath, sourcePath);

    var copiedFile = SpreadsheetDocument.Open(destinationPath, true);
    var fileWithSheets = SpreadsheetDocument.Open("path\\to\\file", false);

    AddCopyOfSheet(fileWithSheets.WorkbookPart, copiedFile.WorkbookPart, "foo");

    using(var stream = new MemoryStream()){
            copiedFile.WorkbookPart.Workbook.Save(stream);
            stream.Position = 0;
            stream.CopyTo(resultsStream);
    }

    return resultsStream;
}

public void CopyFile(string outputFullFilePath, string inputFileFullPath)
{
    int bufferSize = 1024 * 1024;

    using (var fileStream = new FileStream(outputFullFilePath, FileMode.OpenOrCreate))
    {
        var fs = new FileStream(inputFileFullPath, FileMode.Open, FileAccess.ReadWrite);
        fileStream.SetLength(fs.Length);
        int bytesRead = -1;
        byte[] bytes = new byte[bufferSize];

        while ((bytesRead = fs.Read(bytes, 0, bufferSize)) > 0)
        {
            fileStream.Write(bytes, 0, bytesRead);
        }

        fs.Close();
        fileStream.Close();
    }
}

public static void AddCopyOfSheet(WorkbookPart sourceDocument, WorkbookPart destinationDocument, string sheetName)
{
        WorksheetPart sourceSheetPart = GetWorkSheetPart(sourceDocument, sheetName);
        destinationDocument.AddPart(sourceSheetPart);
}

public static WorksheetPart GetWorksheetPart(WorkbookPart workbookPart, string sheetName)
{
        string id = workbookPart.Workbook.Descendants<sheet>().First(x => x.Name.Value.Contains(sheetName)).Id;
        return (WorksheetPart)workbookPart.GetPartById(id);
}

El problema parece surgir de copiedFile.WorkbookPart.Workbook.Save(stream).

Después de que se ejecuta esto, obtengo un error diciendo que hubo una excepción de tipo ‘System.ObjectDisposedException’. El archivo se copia bien y parece que agregar la hoja también funciona.

Esto es lo que he intentado:
1. Usar .Save() sin stream como parámetro. No hace nada.
2. Usar dos streams diferentes (de ahí el jank de resultStream que quedó en este código)
3. Ir puramente a OpenXML y copiar los WorkbookParts a un stream directamente. Probé con un Excel de texto plano y estaba bien, pero rompe el archivo deseado porque tiene un formato avanzado que no parece funcionar bien con OpenXML. Estoy abierto a refactorizar si alguien sabe cómo podría trabajar alrededor de esto, sin embargo.

Lo que no he intentado:
1. Crear OTRA copia de la copia y usar el método SpreadsheetDocument.Create(stream, type). Tengo la sensación de que esto funcionaría pero parece una solución terrible y lenta.
2. Actualizar OpenXML. Actualmente estoy en la versión 2.5.

Cualquier comentario o idea es enormemente apreciado. ¡Gracias!

PD: Mi caja dev está desconectada, así que tuve que escribir este código a mano. Lo siento si hay errores.

Tags:  , ,

Answer

  1. Avatar for davy.ai

    El problema con el código parece estar relacionado con la gestión de memoria. Después de guardar el libro de trabajo en el flujo, se elimina la instancia del libro de trabajo y ya no se puede acceder a él, lo que resulta en una ObjectDisposedException.

    Para solucionar esto, puede intentar crear una nueva instancia de la clase SpreadsheetDocument a partir del flujo de memoria que acaba de escribir. Esto le permitiría acceder al libro de trabajo de nuevo.

    Aquí está una versión actualizada del método ProcessDocument():

    public Stream ProcessDocument()
    {
        var resultStream = new MemoryStream();
    
        string sourcePath = "ruta\\al\\archivo";
        string destinationPath = "ruta\\al\\archivo";
    
        CopyFile(destinationPath, sourcePath);
    
        var copiedFile = SpreadsheetDocument.Open(destinationPath, true);
        var fileWithSheets = SpreadsheetDocument.Open("ruta\\al\\archivo", false);
    
        AddCopyOfSheet(fileWithSheets.WorkbookPart, copiedFile.WorkbookPart, "foo");
    
        // Guardar el libro de trabajo en el flujo
        copiedFile.WorkbookPart.Workbook.Save(resultStream);
    
        // Cerrar copiedFile
        copiedFile.Close();
    
        // Crear una nueva instancia de la clase SpreadsheetDocument a partir del flujo
        var finalFile = SpreadsheetDocument.Open(resultStream, true);
    
        // Cerrar fileWithSheets
        fileWithSheets.Close();
    
        // Copiar el flujo del archivo final al flujo de resultados
        finalFile.Save();
        resultStream = finalFile.Stream;
    
        // Cerrar el archivo final
        finalFile.Close();
    
        return resultStream;
    }
    

    Este método guarda el libro de trabajo en el flujo de resultados, luego cierra la instancia copiedFile. Luego crea una nueva instancia de la clase SpreadsheetDocument a partir del flujo de resultados y lo guarda para actualizar cualquier cambio realizado en el libro de trabajo. Finalmente, copia el flujo del archivo final al flujo de resultados y lo devuelve.

    Tenga en cuenta que este método supone que el archivo ya ha sido copiado y que se ha añadido correctamente una nueva hoja. Los cambios realizados en el libro de trabajo se guardan en el flujo de resultados, que luego se puede devolver.

Comments are closed.