Web services 在web服务器中动态创建流文件存档

Web services 在web服务器中动态创建流文件存档,web-services,haskell,compression,yesod,Web Services,Haskell,Compression,Yesod,我有一个允许上传文件的应用程序(但问题比这个更一般)。我还允许文件加载。我想让用户下载单链接多个文件。根据这个问题:唯一的解决方案似乎是创建包含所有文件的文件归档 我想在Haskell的恒定内存中使用Hackage提供的库来完成,而不需要写入磁盘或执行外部程序 尤其是以下非解决方案: 调用外部程序来创建存档:文件可能位于磁盘上或某个数据库中,可以通过某个远程url访问。文件系统可能是“只读”的。出于安全原因,可能无法执行外部程序。外部程序使部署复杂化 从源文件在磁盘上创建临时存档:请参阅上面的

我有一个允许上传文件的应用程序(但问题比这个更一般)。我还允许文件加载。我想让用户下载单链接多个文件。根据这个问题:唯一的解决方案似乎是创建包含所有文件的文件归档

我想在Haskell的恒定内存中使用Hackage提供的库来完成,而不需要写入磁盘或执行外部程序

尤其是以下非解决方案:

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

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

  • 在内存中创建完整的归档文件并随后提供:这些文件可能相当大(比如CD图像)并且有多个。需要的内存太大了


这在很大程度上取决于您希望支持的文件格式(.zip、.tar.gz、tar.bz2是最常见的),但您可以使用库来创建.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.
import Codec.Archive.Zip
-- ... 在您的代码中:
让拱形模板=
档案文件
{zComment=ByteString.pack“从mysite.com下载”
,zSignature=无
,zEntries=[]
}
让filesIWantToInclude=[“foo.png”、“bar.iso”]

条目如果您在内存中执行此操作,并且有10个用户每人下载5 x 100MB的文件,则仅存档就需要5GB+的RAM。似乎没有特别的可扩展性。@如果你读了这个问题,@Tener明确地不想将整个存档保存在内存中。有很多
gzip
zip
的实现可以动态压缩内容并流式传输。@dflemstr哎呀,错过了问题的最后一部分。尽管如此,即使在中等负载的情况下,这似乎也会摧毁服务器的CPU;在某些情况下,要比SSL加密快得多。你知道吗?它速度如此之快,几乎总是值得去做的。我确实看过这个图书馆。乍一看,这似乎不是一个解决办法。我没有测试它,但从源代码看,readEntry使用toEntry,它试图变得聪明,并且只在需要时进行压缩。测试是通过压缩整个文件并查看是否有帮助来完成的。我认为这将使整个文件存储在内存中,因此整个库将消耗太多内存。不过,手动创建条目是可能的。不过我需要crc32计算的代码。你可以复制内部压缩方法,省去大小比较。。。