Tôi đang viết một chương trình trong đó tệp đầu vào được chia thành nhiều tệp (Lược đồ chia sẻ bí mật của Shamir).Conduit - Nhiều tập tin đầu ra trong đường ống
Dưới đây là các đường ống dẫn Tôi đang tưởng tượng:
- nguồn: sử dụng Conduit.Binary.sourceFile để đọc từ đầu vào
- ống dẫn: Mất một ByteString, sản xuất [ByteString]
- sink: Lấy [ByteString] từ ống dẫn và ghi mỗi ByteString (trong [ByteString]) vào tệp tương ứng của chúng. (Nói nếu đầu vào [ByteString] của chúng tôi được gọi là BSL, sau đó
bsl !! 0
sẽ được ghi vào tập tin 0,bsl !! 1
nộp 1 và vân vân)
Tôi tìm thấy một câu hỏi liên quan file nhiều đầu vào here, nhưng trong trường hợp của họ toàn bộ đường ống được chạy một lần cho mỗi tệp đầu vào, trong khi đối với chương trình của tôi, tôi ghi vào nhiều tệp đầu ra trong đường dẫn.
Tôi cũng đang xem qua mã nguồn Conduit here để xem liệu tôi có thể triển khai multiSinkFile bản thân mình hay không, nhưng tôi hơi bối rối bởi loại tiêu dùng của sinkFile và hơn thế nữa nếu tôi cố gắng đào sâu hơn ... (Tôi vẫn là người mới bắt đầu)
Vì vậy, câu hỏi đặt ra là, tôi nên thực hiện một hàm như multiSinkFile cho phép nhiều tệp được viết như một phần của bồn rửa như thế nào?
Bất kỳ mẹo nào được đánh giá cao!
Làm rõ
Hãy nói rằng chúng tôi muốn làm việc chia sẻ bí mật Shamir về các tập tin có chứa giá trị nhị phân của "ABCDEF" (thành 3 phần).
(Vì vậy, chúng tôi có tập tin của chúng tôi vào srcFile
và các tập tin đầu ra của chúng tôi outFile0
, outFile1
và outFile2
)
Đầu tiên chúng ta đọc "ABC" từ tập tin, và thực hiện xử lý mà sẽ cung cấp cho chúng tôi một danh sách, nói, ["133", "426", "765"]
. do đó "133"
sẽ được ghi vào outFile0
, "426"
đến outFile1
và "765"
đến outFile2
. Và sau đó chúng tôi đọc "DEF" từ srcFile
, xử lý trên đó và ghi kết quả đầu ra tương ứng vào mỗi tệp đầu ra.
EDIT:
Cảm ơn câu trả lời của bạn. Tôi đã đôi khi để hiểu những gì đang xảy ra với ZipSinks vv, và tôi đã viết một chương trình thử nghiệm đơn giản lấy đầu vào của tệp nguồn và chỉ cần ghi nó vào 3 tệp đầu ra. Hy vọng rằng điều này sẽ giúp những người khác trong tương lai.
{-# 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
Bạn có thể cụ thể hơn về cách đầu ra không? Bạn có muốn tạo ra một tệp hoàn chỉnh, sau đó một tệp khác, v.v. không? Hoặc bạn có muốn tạo ra nội dung của họ cùng một lúc, đó là một số dữ liệu để nộp 1, một số dữ liệu để tập 2, sau đó một số dữ liệu để nộp 1 vv? –
Tôi đã thêm một số làm rõ cho câu hỏi. Hy vọng rằng sẽ giúp. –