入力ファイルが複数のファイルに分割されるプログラムを作成しています (シャミールの秘密共有スキーム)。
私が想像しているパイプラインは次のとおりです。
- source: Conduit.Binary.sourceFile を使用して入力から読み取ります
- コンジット: ByteString を受け取り、[ByteString] を生成します
- シンク:コンジットから [ByteString] を取得し、各 ByteString ([ByteString] 内) を対応するファイルに書き込みます。(たとえば、入力 [ByteString] が bsl と呼ばれる場合、
bsl !! 0
ファイル 0、bsl !! 1
ファイル 1 などに書き込まれます)
ここで複数の入力ファイルに関する質問を見つけましたが、その場合、入力ファイルごとにパイプライン全体が 1 回実行されますが、私のプログラムでは、パイプライン内の複数の出力ファイルに書き込みます。
また、ここでConduit のソース コードを調べて、自分で multiSinkFile を実装できるかどうかを確認していますが、sinkFile の Consumer 型に少し戸惑っています。まだ初心者です)
問題は、複数のファイルをシンクの一部として書き込むことを可能にする multiSinkFile のような関数をどのように実装すればよいかということです。
どんなヒントでも大歓迎です!
明確化
「ABCDEF」のバイナリ値 (3 つの部分) を含むファイルで Shamir の秘密共有を行いたいとします。
(つまり、入力ファイルsrcFile
と出力ファイルoutFile0
がoutFile1
ありますoutFile2
)
最初にファイルから「ABC」を読み取り、たとえば、のリストを取得する処理を行います["133", "426", "765"]
。soは to 、to 、to"133"
に書き込まれます。そして、 から「DEF」を読み取り、処理を行い、対応する出力を各出力ファイルに書き込みます。outFile0
"426"
outFile1
"765"
outFile2
srcFile
編集:
回答ありがとうございます。ZipSinks などで何が起こっているのかを理解するのに時間がかかり、ソース ファイルの入力を取得して 3 つの出力ファイルに単純に書き込む簡単なテスト プログラムを作成しました。うまくいけば、これは将来他の人に役立つでしょう。
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE OverloadedStrings #-}
import ClassyPrelude.Conduit
import Safe (atMay)
import Text.Printf
import Filesystem.Path.CurrentOS (decodeString, encodeString)
import Control.Monad.Trans.Resource (runResourceT, ResourceT(..))
-- get the output file name given the base (file) path and the split number
getFileName :: FilePath -> Int -> FilePath
getFileName basePath splitNumber = decodeString $ encodeString basePath ++ "." ++ printf "%03d" splitNumber
-- Get the sink file, given a filepath generator (that takes an Int) and the split number
idxSinkFile :: MonadResource m
=> (Int -> FilePath)
-> Int
-> Consumer [ByteString] m ()
idxSinkFile mkFP splitNumber =
concatMapC (flip atMay splitNumber) =$= sinkFile (mkFP splitNumber)
sinkMultiFiles :: MonadResource m
=> (Int -> FilePath)
-> [Int]
-> Sink [ByteString] m ()
sinkMultiFiles mkFP splitNumbers = getZipSink $ otraverse_ (ZipSink . idxSinkFile mkFP) splitNumbers
simpleConduit :: Int -> Conduit ByteString (ResourceT IO) [ByteString]
simpleConduit num = mapC (replicate num)
main :: IO ()
main = do
let mkFP = getFileName "test.txt"
splitNumbers = [0..2]
runResourceT $ sourceFile "test.txt" $$ simpleConduit (length splitNumbers) =$ sinkMultiFiles mkFP splitNumbers