Using System.IO.Compression.ZipArchive for zipping does not work with F # code

I am trying to create a zip file from an array of bytes in F # with the following script. The file is created correctly, but when I try to open it, I have an error.

When I tried to unzip the byte array from the function zipFile, I gotSystem.IO.InvalidDataException: End of Central Directory record could not be found.

Am I doing something wrong in a function zipFile?

#if INTERACTIVE
#r "System.IO.Compression.dll"
#endif

open System.IO
open System.IO.Compression
open System.Linq

let zipFile (fileName: string) (data: byte []) =
    try
        use ms = new MemoryStream()
        use archive = new ZipArchive(ms, ZipArchiveMode.Create)

        let entry = archive.CreateEntry(fileName)
        use entryStream = entry.Open()
        use bw = new BinaryWriter(entryStream)
        bw.Write(data)

        Ok (ms.ToArray())
    with e ->
        Error <| sprintf "Cannot zip stream %s: %s" fileName e.Message

let saveFile path fileName (data: byte []) =
    try
        use fs = File.Open(Path.Combine(path, fileName + ".zip"), FileMode.OpenOrCreate)
        fs.Write(data, 0, data.Length)
        Ok ()
    with e ->
        Error <| sprintf "Cannot save file %s: %s" fileName e.Message

let data = "test" |> System.Text.Encoding.UTF8.GetBytes
let filename = "data.txt"

data
|> zipFile filename
|> Result.bind (saveFile "C:\\temp" filename)
|> printfn "%A"
+4
source share
1 answer

You need finer control when various resources are involved IDisposable, so the contents are ZipArchivecompletely cleared before MemoryStreamyou return an array of bytes:

let zipFile (fileName: string) (data: byte []) =
    try
        use ms = new MemoryStream()
        (
          use archive = new ZipArchive(ms, ZipArchiveMode.Create)
          let entry = archive.CreateEntry(fileName)
          use entryStream = entry.Open()
          use bw = new BinaryWriter(entryStream)
          bw.Write(data)
        )
        Ok (ms.ToArray())
    with e ->
        Error <| sprintf "Cannot zip stream %s: %s" fileName e.Message

You can use parentheses (...)to add an explicit / nested area for bindings use.

+6
source

Source: https://habr.com/ru/post/1694050/


All Articles