我正在编写一个程序,其中将输入文件拆分为多个文件(Shamir的秘密共享方案)。
这是我在想的管道:
bsl !! 0
它将被写入文件0,bsl !! 1
文件1,依此类推)我在这里发现了有关多个输入文件的问题,但在这种情况下,整个管道对每个输入文件只运行一次,而对于我的程序,我正在向管道中的多个输出文件进行写入。
我还在这里浏览Conduit源代码,看我是否可以自己实现multiSinkFile,但是我对ConsumerFile的sinkFile类型有些困惑,如果我尝试更深入地研究它,那就更是如此...(我是还是个初学者)
所以,问题是,我应该如何实现像multiSinkFile这样的功能,该功能允许将多个文件作为接收器的一部分写入?
任何提示表示赞赏!
澄清度
假设我们要对包含“ ABCDEF”的二进制值(分为3部分)的文件进行Shamir's Secret共享。
(因此,我们有输入文件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
有多种方法可以执行此操作,具体取决于您是要动态增加要写入的文件数,还是只是保持固定的数目。这是一个带有固定文件列表的示例:
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ViewPatterns #-}
import ClassyPrelude.Conduit
import Safe (atMay)
idxSinkFile :: MonadResource m
=> (Int -> FilePath)
-> Int
-> Consumer [ByteString] m ()
idxSinkFile mkFP idx =
concatMapC (flip atMay idx) =$= sinkFile fp
where
fp = mkFP idx
sinkMultiFiles :: MonadResource m
=> (Int -> FilePath)
-> [Int]
-> Sink [ByteString] m ()
sinkMultiFiles mkFP indices = getZipSink $ otraverse_ (ZipSink . idxSinkFile mkFP) indices
someFunc :: ByteString -> [ByteString]
someFunc (decodeUtf8 -> x) = map encodeUtf8 [x, toUpper x, toLower x]
mkFP :: Int -> FilePath
mkFP 0 = "file0.txt"
mkFP 1 = "file1.txt"
mkFP 2 = "file2.txt"
src :: Monad m => Producer m ByteString
src = yieldMany $ map encodeUtf8 $ words "Hello There World!"
main :: IO ()
main = do
let indices = [0..2]
runResourceT $ src $$ mapC someFunc =$ sinkMultiFiles mkFP indices
forM_ indices $ \idx -> do
let fp = mkFP idx
bs <- readFile fp
print (fp, bs :: ByteString)
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句