首页 > 解决方案 > 如何在 Haskell 中高效地写入大文件

问题描述

您好,我正在尝试及时写入~1GB文件。有没有推荐的方法。到目前为止,该过程大约需要几十分钟。我使用错了我Text应该使用ByteString吗?(我也用过String

    pt="d:\\data2.csv"
    cnt=400000000

    main::IO()
    main=do
        let payload=dat
        writeWithHandle pt dat


    dat::Text
    dat=Data.Text.pack "0744442339"


    writeWithHandle::FilePath->Text->IO()
    writeWithHandle path tx=do
        handle<-openFile path WriteMode
        writeTimes cnt handle dat

    writeTimes::Int->Handle->Text->IO()
    writeTimes cnt handle payload= forM_ ([0..cnt])  (\x->Data.Text.IO.hPutStrLn handle payload)

我不明白为什么它需要花费数十分钟的时间。最初我正​​在使用writeFile,但我认为这将意味着不断打开和关闭file每一行,所以我过去appendFile无济于事。

标签: performancehaskelliowritefile

解决方案


我建议为此使用 Builder,这是一种填充缓冲区的有效方法,并且可以直接写入 Handle。

#!/usr/bin/env stack
-- stack --resolver ghc-8.6.4 script
{-# LANGUAGE OverloadedStrings #-}
import Data.ByteString.Builder (Builder, hPutBuilder)
import Data.Foldable (fold)
import System.IO (IOMode (WriteMode), withBinaryFile)

pt :: FilePath
pt = "data2.csv"

cnt :: Int
cnt = 400000000

main :: IO ()
main = writeWithHandle pt dat

dat :: Builder
dat = "0744442339"

writeWithHandle :: FilePath -> Builder -> IO ()
writeWithHandle path tx =
  withBinaryFile path WriteMode $ \h ->
  hPutBuilder h $ makeBuilder cnt tx

makeBuilder :: Int -> Builder -> Builder
makeBuilder cnt payload = fold $ replicate cnt $ payload <> "\n"

如果您愿意,您可以保留payload为值,然后转换为using 。TextBuilderencodeUtf8Builder


推荐阅读