我有一个Yesod应用程序(但问题比这更通用)允许文件上传。我也允许文件下载。我想允许用户使用单个链接下载多个文件。根据这个问题:How to download multiple files with one HTTP request?唯一的解决方案似乎是创建包含所有文件的文件存档。
我希望使用Hackage中的库在Haskell的常量内存中执行此操作,而无需写入磁盘或执行外部程序。
特别是以下是非解决方案:
调用外部程序来创建存档:文件可能位于磁盘上或某些数据库中,可通过某些远程URL访问。文件系统可以是“只读”。出于安全原因,可能无法执行外部程序。外部程序使部署复杂化。
从源文件在磁盘上创建临时存档:请参阅上面的“只读”文件系统。效率也很低:实际上写入磁盘非常慢。
在内存中创建完整的存档并在之后提供:文件可能非常大(想想CD图像)和多个。所需的记忆力太大了。
答案 0 :(得分: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
函数生成条目。值得一提的是eRelativePath
中的Entry
字段是.zip存档内文件的相对路径,而不是文件系统中的实际相对路径。