各位程序员,您好。
因此,我决定重写在Haskell中闲逛的一些旧脚本,只是因为我需要练习并且我喜欢这种语言。因此,在这里,我尝试过滤一个巨大的文件(大约1.7 GB),切掉不感兴趣的行,并将其余内容写入另一个文件中。

我以为haskell的懒惰特性对此很理想,但是代码总是太快耗尽内存。以前的版本(C#或Python)具有读取行->写入行方法,但是我在这里尝试了另一种方法。我应该重写代码以镜像以前的版本还是我遗漏了什么。

因此,这是负责原始文件过滤的功能:

getLines :: FilePath -> IO [[String]]
getLines path = do
    text<-readFile path
    let linii=lines text
    let tokens = map words linii
    let filtrate=[x|x<-tokens,length x>7,isTimeStamp (x!!0),isDiagFrame x]
    return filtrate

这个负责在新文件中一次写一行(虽然我试图直接使用writeFile并不幸失败了:):
writeLines ::Handle->[[String]]->IO ()
writeLines handle linii = do
                    let linie=concat $ intersperse " " (head  linii)
                    hPutStrLn handle linie
                    if length linii > 0     then
                                    writeLines handle  (tail linii)
                                        else
                                    print "Writing complete..."

这两个是主要功能,另一个负责获取并传递手柄:
writeTheFile :: FilePath->FilePath->IO ()
writeTheFile inf outf = do
handle<-openFile outf WriteMode
linii<-getLines inf
writeLines handle linii
print "Write Complete"


main = do
arg<-getArgs
if length arg/=2    then
    print "Use like this : trace_pars [In_File] [Out_File] !"
                    else
    writeTheFile (arg!!0) (arg!!1)

任何建议将不胜感激...提前感谢

最佳答案

这里的问题在这一行:

                    if length linii > 0     then

您正在计算行列表的长度。这意味着必须加载整个行列表才能进行计数。这意味着您正在读取的整个文件需要加载到内存中。不好!

解决方案是改用if not . null $ linii thennull函数检查列表是否为空(这仅强制加载列表的第一行),并且not的行为与您期望的一样。

如果您想使用更惯用的writeLines版本(请注意,使用FilePath代替Handle):
writeLines :: FilePath -> [[String]] -> IO ()
writeLines filename = writeFile filename . unlines . map unwords

此功能与以下功能相同:
writeLines filename lines =
  writeFile filename mergedFile
  where
    mergedFile = unlines mergedLines
    mergedLines = map unwords lines
unlinesintercalate "\n"相同,并且unwordsintercalate " "相同。 intercalate xconcat . intersperse x相同。

我认为这应该是足够的信息,让您了解正在发生的事情。

10-05 18:16