Hello编程员。 所以我决定重写我在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)
非常感谢任何建议......提前感谢
答案 0 :(得分:14)
问题出在这一行:
if length linii > 0 then
您正在计算行列表的长度。这意味着必须加载整个行列表才能对其进行计数。这意味着您正在阅读的整个文件需要加载到内存中。不好!</ p>
解决方案是使用if not . null $ linii then
代替。 null
函数检查列表是否为空(仅强制列表的第一行加载),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
unlines
与intercalate "\n"
相同,unwords
与intercalate " "
相同。 intercalate x
与concat . intersperse x
相同。
我认为这应该足以让您了解正在发生的事情。