2017-03-08 26 views
4

我想知道是否有一種簡單的方法,一次只能將一行文件從文件中取出,而不會最終將整個文件加載到內存中。我想用一個attoparsec解析器來完成這一行。我嘗試使用Data.Text.Lazy.IOhGetLine,這讓我的記憶力大打折扣。我後來閱讀,最終加載整個文件。在無緩衝的情況下讀取大文件中的大行

s <- Pipes.sum $ 
    folds (\i _ -> (i+1)) 0 id (view Text.lines (Text.fromHandle handle)) 
print s 

僅計算行數,它似乎是在做一些靠不住的東西「hGetChunk:無效的參數(無效字節序列

我也使用管道文本foldsview lines嘗試)「,需要11分鐘,wc -l需要1分鐘。我聽說管道文本可能有一些問題與巨大的線? (每行大約1GB)

我真的很樂意提供任何建議,除了新手readLine怎麼樣都找不到。

謝謝!

+3

您正在使用Pipes.Text.IO進行輸入,而不是像庫建議的那樣使用Pipes.Bytestring +解碼。該錯誤消息來自正在對每個塊進行系統解碼的判斷的文本庫。我認爲它是說它不能根據它認爲的編碼來理解塊。 – Michael

回答

6

下面的代碼使用導管,以及將:只要有可用

  • 對於每個行多個數據

    • UTF8解碼標準輸入
    • 運行lineC組合子,只需yield1並丟棄行內容,不會一次將整行讀入內存
    • 總結1 s產生並打印

    您可以將yield 1代碼替換爲將在各行上處理的內容。

    #!/usr/bin/env stack 
    -- stack --resolver lts-8.4 --install-ghc runghc --package conduit-combinators 
    import Conduit 
    
    main :: IO() 
    main = (runConduit 
        $ stdinC 
        .| decodeUtf8C 
        .| peekForeverE (lineC (yield (1 :: Int))) 
        .| sumC) >>= print 
    
  • +1

    哇,太棒了! 1m23s vs 1m5s爲「wc -l」,謝謝! –

    +0

    很高興聽到它,感謝您報告時間。 –

    +0

    不知道這是不是最好的地方要問,但是當我用3C int常量大小的monoid在我的分析過的線上做一個foldC來代替sumC時,它似乎再次吹掉我所有的記憶。我什麼都沒有留下?我也試過foldlC。 –

    3

    這可能比較容易爲摺疊在解碼文本流

    {-#LANGUAGE BangPatterns #-} 
    import Pipes 
    import qualified Pipes.Prelude as P 
    import qualified Pipes.ByteString as PB 
    import qualified Pipes.Text.Encoding as PT 
    import qualified Control.Foldl as L 
    import qualified Control.Foldl.Text as LT 
    main = do 
        n <- L.purely P.fold (LT.count '\n') $ void $ PT.decodeUtf8 PB.stdin 
        print n 
    

    它需要比wc -l爲我公司生產的文件,它只是逗號長和數字的線長大約14%。正如文檔所述,IO應該正確地使用Pipes.ByteString來完成,其餘的是各種便利。

    您可以在每行上映射一個attoparsec解析器,區別爲view lines,但請記住,attoparsec解析器可以根據需要累積整個文本,這對於1 GB大小的文本可能不是一個好主意。如果每行有重複的數字(例如單詞分隔的數字),您可以使用Pipes.Attoparsec.parsed來傳輸它們。

    +0

    謝謝!當我有機會時,我也會試試這個 –

    相關問題