我正在编写一个程序,其中输入文件被拆分为多个文件(Shamir 的秘密共享方案)。
这是我想象的管道:
- 来源:使用 Conduit.Binary.sourceFile 从输入中读取
- 管道:接受一个 ByteString,产生 [ByteString]
- sink:从管道中获取 [ByteString],并将每个 ByteString(在 [ByteString] 中)写入其相应的文件。(假设我们的输入 [ByteString] 被称为 bsl,那么
bsl !! 0
将被写入文件 0、bsl !! 1
文件 1 等等)
我在这里发现了一个关于多个输入文件的问题,但在他们的情况下,整个管道为每个输入文件运行一次,而对于我的程序,我正在写入管道中的多个输出文件。
我也在查看这里的 Conduit 源代码,看看我是否可以自己实现一个 multiSinkFile,但我对 sinkFile 的 Consumer 类型有点困惑,如果我尝试更深入地挖掘,更是如此......(我是还是初学者)
所以,问题是,我应该如何实现像 multiSinkFile 这样的函数,它允许将多个文件作为接收器的一部分写入?
任何提示表示赞赏!
澄清
假设我们要对包含二进制值“ABCDEF”(分为 3 部分)的文件进行 Shamir 的秘密共享。
(所以我们有我们的输入文件srcFile
和我们的输出文件outFile0
,outFile1
和outFile2
)
我们首先从文件中读取“ABC”,然后进行处理,这将为我们提供一个列表,例如["133", "426", "765"]
. 所以"133"
将被写入到outFile0
,"426"
到outFile1
和"765"
到outFile2
。然后我们从 中读取“DEF” 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