Cómo usar OpenXML SDK con F# y MemoryStreams

Este artículo dice que necesita usar MemoryStreams redimensionables cuando trabaja con OpenXML SDK, y el código de muestra funciona bien.

Sin embargo, cuando traduzco el código C# de muestra a F#, el documento permanece sin cambios:

open System.IO
open DocumentFormat.OpenXml.Packaging
open DocumentFormat.OpenXml.Wordprocessing

[<EntryPoint>]
let Main args =
    let byteArray = File.ReadAllBytes "Test.docx"

    use mem = new MemoryStream()
    mem.Write(byteArray, 0, (int)byteArray.Length)

    let para = new Paragraph()
    let run = new Run()
    let text = new Text("Newly inserted paragraph")
    run.InsertAt(text, 0) |> ignore
    para.InsertAt(run, 0) |> ignore

    use doc = WordprocessingDocument.Open(mem, true)
    doc.MainDocumentPart.Document.Body.InsertAt(para, 0) |> ignore

    // no change to the document
    use fs = new FileStream("Test2.docx", System.IO.FileMode.Create)
    mem.WriteTo(fs)

    0

Funciona bien cuando uso WordprocessingDocument.Open("Test1.docx", true), pero quiero usar un MemoryStream. ¿Qué estoy haciendo mal?

preguntado el 22 de mayo de 12 a las 13:05

1 Respuestas

Cambios que estás haciendo en doc no se reflejan en MemoryStream mem hasta que cierres doc. Colocación doc.Close() como a continuación

...
doc.MainDocumentPart.Document.Body.InsertAt(para, 0) |> ignore 
doc.Close()
...

soluciona el problema y recibirás un mensaje de texto Newly inserted paragraph en la parte superior de tu Test2.docx.

Además, a su fragmento le falta una referencia obligatoria:

open DocumentFormat.OpenXml.Packaging 

del WindowsBase.dll.

EDITAR: como señaló ildjarn, más F#-idiomático sería la siguiente refactorización:

open System.IO
open System.IO.Packaging
open DocumentFormat.OpenXml.Packaging 
open DocumentFormat.OpenXml.Wordprocessing 

[<EntryPoint>] 
let Main args = 
    let byteArray = File.ReadAllBytes "Test.docx" 

    use mem = new MemoryStream() 
    mem.Write(byteArray, 0, (int)byteArray.Length) 

    do
        use doc = WordprocessingDocument.Open(mem, true) 
        let para = new Paragraph() 
        let run = new Run() 
        let text = new Text("Newly inserted paragraph") 
        run.InsertAt(text, 0) |> ignore     
        para.InsertAt(run, 0) |> ignore
        doc.MainDocumentPart.Document.Body.InsertAt(para, 0) |> ignore 

    use fs = new FileStream("Test2.docx", FileMode.Create) 
    mem.WriteTo(fs) 

    0 

contestado el 22 de mayo de 12 a las 17:05

Personalmente, pondría use doc = ... y la siguiente línea en un do bloquear en lugar de llamar Close() a mano. - ildjarn

@mcmc: en el fragmento de MSDN C# "doc.Close()" se realiza implícitamente por using (WordprocessingDocument wordDoc = ... {... }; eliminación automática sobre la {...} descargas de salida de bloque todos los wordDoc datos a MemoryStream. A su puerto F# inicial le faltaba esta sutileza. La versión refactorizada de F# aplica el mismo patrón: doc el rubor ocurre al salir do envoltura de bloqueuse doc... pieza. - gen belitski

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.