【问题标题】:Cannot create ZipArchive in F#无法在 F# 中创建 ZipArchive
【发布时间】:2016-12-14 00:44:32
【问题描述】:

我正在尝试在 F# 项目中实例化 System.IO.Compression 中的 ZipArchive 类:

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)

我可以在 C# 中的正确命名空间中创建相同的东西:

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

(这会产生一堆错误,因为我传递的是 null,但至少我可以尝试访问它)。

确实在我的 F# 项目中有 System.IO.Compression.FileSystem 引用(以及父命名空间 System.IO.Compression。但是,在加载 .FileSystem 命名空间时,我收到一条错误消息“命名空间 'FileSystem' 未定义”。

编辑

添加了我正在尝试执行的完整脚本文件以重现问题。

open 语句所示,我的项目引用了这两个库:

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

我正在运行:

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

编辑 2:修复!

我在 F# 脚本文件 .fsx 中执行所有这些操作,这需要告诉交互式环境像这样加载 DLL:

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

【问题讨论】:

  • 虽然您需要同时引用 Compression 和 Compression.Filesystem,但您通常只需 open System.IO.Compression。然后你可以说new ZipArchive(x)) 并进一步操作它。
  • 请描述您遇到的问题。编译失败了吗?如果是这样,错误信息是什么?它在运行时会失败吗?如果有,有哪些例外?
  • @MarkSeemann 我已经用更多细节更新了我的问题。

标签: f# zip compression unzip


【解决方案1】:

您可以使用 System.IO.Compression 从 .NET 4.5 操作 zip 文件。一些使用示例请参见relevant docs

您可以将 FileStream 包装到ZipArchive,然后进一步操作它。 ExtractToDirectory 扩展方法非常方便。您可以创建一个 FileStream,实例化 ZipArchive,然后进一步操作它,例如使用CreateEntryFromFile 扩展方法,理想情况下,您应该尝试在一次性使用use,如writeZipFile 示例中所示。

下面是一个读写压缩文件的例子:

#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

【讨论】:

  • 看起来需要if INTERACTIVE 位才能使其工作属性 - 添加它可以将所有内容联系在一起。这是因为我在 F# 脚本文件而不是常规 F# 文件中执行此操作吗?
  • @Max 是的。或者更确切地说,因为我假设您将其发送给 Fsi,您需要 #r 指令来引用 dll。如果您(必须)安装了可视 f# 工具,您可以右键单击 vs 中的引用并选择发送到交互式。然后只需复制粘贴路径。您还可以生成包含 fsx 脚本。
【解决方案2】:

您可能缺少对System.IO.Compression.dll 的引用。

GZipStreamSystem.IO.Compression 命名空间,但在System.dll 程序集

ZipArchive 也在System.IO.Compression 命名空间 中,但System.IO.Compression.dll 程序集 默认情况下可能没有添加到您的F# 项目中。 p>

【讨论】:

  • 我添加了对项目的引用,包括CompressionFileSystem。我仍然无法访问ZipArchive 类。
  • 奇怪 - 有了这些引用,我可以让代码编译得很好。 (控制台应用、F# Core 4.4、.net 4.6、VS2015)
猜你喜欢
  • 1970-01-01
  • 2017-10-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-14
  • 1970-01-01
  • 2014-03-28
相关资源
最近更新 更多