0

ファイルのアップロードを許可するYesodアプリケーションがあります (ただし、質問はこれよりも一般的です)。ファイルのダウンロードも許可します。ユーザーが単一のリンクで複数のファイルをダウンロードできるようにしたいと思います。この質問に従って: 1 つの HTTP 要求で複数のファイルをダウンロードする方法は? 唯一の解決策は、すべてのファイルを含むファイルアーカイブを作成することです。

ディスクに書き込んだり、外部プログラムを実行したりせずに、Hackage のライブラリを使用して、Haskell の一定のメモリで実行したいと考えています。

特に、以下は非解決策です。

  • 外部プログラムを呼び出してアーカイブを作成します。ファイルはディスク上にあるか、リモートURLからアクセスできるデータベースにあります。ファイルシステムは「読み取り専用」である可能性があります。セキュリティ上の理由から、外部プログラムを実行できない場合があります。外部プログラムは展開を複雑にします。

  • ソースファイルからディスク上に一時アーカイブを作成: 上記の「読み取り専用」ファイルシステムを参照してください。また、非常に非効率的です。ディスクへの書き込みは実際にはかなり遅いです。

  • メモリ内に完全なアーカイブを作成し、後でそれを提供します。ファイルは非常に大きく (CD イメージを考えてください)、複数になる場合があります。必要なメモリが多すぎます。

4

1 に答える 1

1

サポートするファイル形式によって大きく異なりますが (.zip、.tar.gz、tar.bz2 が最も一般的です)、zip-archiveライブラリを使用して .zip アーカイブを作成できます。これらのアーカイブは遅延バイト文字列として生成されます。つまり、オンザフライで生成されます。唯一のトリッキーな部分はArchive、正しい内容で type の値を生成することです。たとえば、次のようになります。

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 アーカイブ内のファイルの相対パスであることに注意してください。

于 2012-06-08T11:15:50.437 に答える