【问题标题】:Shortest code to read a file and then update it?读取文件然后更新它的最短代码?
【发布时间】:2016-10-01 09:37:27
【问题描述】:

我需要在同一个函数中读取、修改然后更新一些文件。理想的解决方案(见下文)行不通,这是错误的。 “最差”的解决方案有效。

-- Ex. "Pseudocode" - Doesn't work.
ideal = let pathFile = "C:\\TEMP\\Foo.txt" 
           in readFile pathFile >>= writeFile pathFile . (++ "!")

-- It works. 
worst = do
    let pathFile = "C:\\TEMP\\Foo.txt"
    h <- openFile pathFile ReadMode
    cs <- hGetContents h 
    (temp_Foo,temp_handle) <- openTempFile pathFile
    hPrint temp_handle $ cs ++ "!"
    hClose temp_handle
    removeFile pathFile
    renameFile temp_Foo pathFile

我宁愿避免 Reid Burton 在 2010 年提出的“简单但丑陋的解决方法”:

doit file = do
    contents <- readFile file
    length contents `seq` (writeFile file $ process contents)

有没有更好的解决方案?

【问题讨论】:

  • 好吧,您可以使用导管/管道解决方案。 :)
  • @Sibi 这些库非常庞大。我认为这需要很长时间才能掌握。另外,我不认为用大炮杀死蚊子。
  • @AlbertoCapitani 你不需要大炮来杀死蚊子——但你也不需要超级计算机(按照 70 年代的标准)来打电话。
  • 如果您使用import qualified Data.Text.IO as T,则您有严格的文本,ideal 工作正常T.readFile pathFile &gt;&gt;= T.writeFile pathFile . (&lt;&gt; "!")text 包是处理文本的标准方法。
  • @Michael 谢谢你,但我选择这个例子只是为了简单。我使用集合和地图以及其他更复杂的结构。

标签: haskell io


【解决方案1】:

ideal 的问题在于它懒惰地读取字符串,即在您尝试再次打开它进行写入之前,该文件尚未完全在内存中。

这种懒惰现在被广泛认为是一个坏主意 – 如果您确实需要这种即读即读功能,那么conduit/pipes 就是您所需要的想要。

在您的示例中,您实际上并不需要懒惰,除非文件太大而不能保证立即将其放入内存中。所以你可以只使用readFile,但需要严格:手动的方法是

ideal = do
    fc <- readFile pathFile
    length fc `seq` writeFile pathFile (fc++ "!")
 where pathFile = "C:\\TEMP\\Foo.txt"

这里我使用了length 来确保字符串真的被评估到最后。确保同样事情的更好方法是使用deepseq

ideal = do
    fc <- readFile pathFile
    fc `deepseq` writeFile pathFile (fc++ "!")

...或者,如果你想要它没有点,

ideal = readFile pathFile >>= (writeFile pathFile . (++ "!") $!!)

请注意,readFile 的更现代变体具有比String 更有效的类型——尤其是Data.Text.readFile——不需要这些,因为它们是开箱即用的。因此,以下方法可以正常工作,并且可能是最好的解决方案:

{-# LANGUAGE OverloadedStrings #-}

import Prelude hiding (readFile, writeFile)
import Data.Text.IO
import Data.Monoid ((<>))

main :: IO ()
main = readFile pathFile >>= writeFile pathFile . (<> "!")
 where pathFile = "/tmp/foo.txt"

在 Haskell 的早期,所有的“交错 IO”实际上都是基于惰性,因此旧的库有点被它淹没了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-20
    • 2015-01-17
    • 2016-06-11
    • 1970-01-01
    • 2014-02-20
    相关资源
    最近更新 更多