Cannot create ZipArchive in F#
Asked Answered
T

2

5

I am trying to instantiate a ZipArchive class in System.IO.Compression in an F# project:

open System.IO
open System.IO.Compression
open System.IO.Compression.FileSystem //this line errors, as expected

// Define your library scripting code here

let directoryPath = @"C:\Users\max\Downloads"

let dirInfo = new DirectoryInfo(directoryPath)

let zippedFiles = dirInfo.GetFiles() 
|> Array.filter (fun x -> x.Extension.Equals(".zip"))

let fileStream = new FileStream(((Array.head zippedFiles).FullName), System.IO.FileMode.Open)

//this line does not compile, because ZipArchive is not defined
let archive = new System.IO.Compression.ZipArchive(fileStream)

I can create the same thing in C# in the correct namespace:

var unzipper = new System.IO.Compression.ZipArchive(null);

(This gives a bunch of errors because I'm passing null, but at least I can try to access it).

I do have the System.IO.Compression.FileSystem reference in my F# project (as well as the parent namespace, System.IO.Compression. However, when loading the .FileSystem namespace, I get an error saying "the namespace 'FileSystem' is not defined".

EDIT

Added the full script file I am trying to execute that reproduces the problem.

As shown via the open statements, my project references both of these libraries:

System.IO.Compression System.IO.Compression.FileSystem

I am running on:

  • F# 4.4
  • .NET 4.6.1
  • Visual Studio 2015
  • Windows 10 64 bit

EDIT 2: The Fix!

I was doing all of this in an F# script file, .fsx, which requires telling the interactive environment to load the DLLs like so:

#if INTERACTIVE
#r "System.IO.Compression.dll"
#r "System.IO.Compression.FileSystem.dll"
#endif
Theiss answered 14/12, 2016 at 0:44 Comment(3)
while you need to reference both Compression and Compression.Filesystem, you usually only open System.IO.Compression. Then you can just say new ZipArchive(x)) and manipulate it further.Beerbohm
Please describe the problem you're having with this. Does it fail to compile? If so, what's the error message? Does it fail at run-time? If so, what are the exceptions?Phosphorus
@MarkSeemann I have updated my question with additional details.Theiss
B
4

You can use System.IO.Compression to manipulate zip files from .NET 4.5. For some useage examples please see the relevant docs.

You can just wrap the FileStream into ZipArchive, then manipulate it further. The ExtractToDirectory extension method is quite handy. You can create a FileStream, instantiate ZipArchive, then manipulate it further, for example by using the CreateEntryFromFile extension method, Ideally you should try using use on disposable as in the writeZipFile example.

Here's an example of reading and writing a zipfile:

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

open System.IO
open System.IO.Compression

let zipfile = @"c:\tmp\test.zip"
File.Exists zipfile //true

let readZipFile (x:string) = 
    let x = new FileStream(x,FileMode.Open,FileAccess.Read)
    new ZipArchive(x)

let z = readZipFile zipfile
z.ExtractToDirectory(@"c:\tmp\test")
File.Exists @"c:\tmp\test\test.txt" // true

let writeZipFile (x:string) =
    use newFile = new FileStream(@"c:\tmp\newzip.zip",FileMode.Create)
    use newZip =  new ZipArchive(newFile,ZipArchiveMode.Create)
    newZip.CreateEntryFromFile(@"c:\tmp\test.txt","test.txt")

writeZipFile @"c:\tmp\test.txt"
File.Exists @"c:\tmp\newzip.zip"  // true
Beerbohm answered 14/12, 2016 at 8:33 Comment(2)
It looks like that if INTERACTIVE bit is required for this to work property - adding that got everything to tie together. Is this because I am doing this in a F# script file and not a regular F# file?Theiss
@Theiss yes. Or rather because I assume you are sending this to Fsi, you need the #r directive to reference the dll. If you have (a must) visual f# tools installed yoi can right click on the refernce in vs and select send to interactive. Then just copy-paste the path. You can also generate an include fsx script.Beerbohm
C
3

You are probably missing a reference to System.IO.Compression.dll.

GZipStream is in the System.IO.Compression namespace, but the System.dll assembly.

ZipArchive is also in the System.IO.Compression namespace, but the System.IO.Compression.dll assembly which may not have been added to your F# project by default.

Collegiate answered 14/12, 2016 at 13:20 Comment(2)
I added the reference to the project, both for Compression and for FileSystem. I still can't access the ZipArchive class.Theiss
Strange - with those references, I can get that code to compile fine. (Console app, F# Core 4.4, .net 4.6, VS2015)Collegiate

© 2022 - 2024 — McMap. All rights reserved.