0

我有一个允许文件上传的Yesod应用程序(但问题比这更笼统)。我也允许文件下载。我想允许用户使用单个链接下载多个文件。根据这个问题:如何使用一个 HTTP 请求下载多个文件?唯一的解决方案似乎是创建包含所有文件的文件存档。

我想使用来自 Hackage 的库在 Haskell 的常量内存中执行此操作,而无需写入磁盘或执行外部程序。

特别是以下是非解决方案:

  • 调用外部程序来创建存档:文件可能在磁盘上,也可能在某个数据库中,可以通过某个远程 URL 访问。文件系统可能是“只读的”。出于安全原因,可能无法执行外部程序。外部程序使部署复杂化。

  • 从源文件在磁盘上创建临时存档:参见上面的“只读”文件系统。效率也很低:实际上写入磁盘非常慢。

  • 在内存中创建完整的存档并在之后提供它:文件可能非常大(想想 CD 图像)和多个。需要的内存太大了。

4

1 回答 1

1

这在很大程度上取决于您想要支持的文件格式(.zip、.tar.gz、tar.bz2 是最常见的),但您可以使用该zip-archive库来创建 .zip 存档。这些档案是作为惰性字节字符串生成的,这意味着它们将即时生成。唯一棘手的部分是生成Archive具有正确内容的类型值。例如,它可能看起来像这样:

import Codec.Archive.Zip

-- ... and in your code:
let archiveTemplate =
  Archive
  { zComment = ByteString.pack "Downloaded from mysite.com"
  , zSignature = Nothing
  , zEntries = []
  }

let filesIWantToInclude = ["foo.png", "bar.iso"]
entries <- forM filesIWantToInclude $ readEntry []
let archive = foldr addEntryToArchive archiveTemplate entries

let byteString = fromArchive archive
-- Now you can send the byteString over the network, or something.

如果您的文件系统上没有要压缩的文件,而是数据库中的文件或其他文件,则可以手动构建类型Entry的值并填写正确的字段。您只需要一个惰性ByteString表示您想要的数据压缩,仅此而已;然后您可以使用该toEntry函数生成一个条目。值得一提的是,eRelativePathin 字段Entry是 .zip 存档中文件的相对路径,而不是文件系统中的实际相对路径。

于 2012-06-08T11:15:50.437 回答