找回密码
 加入
搜索
查看: 1907|回复: 9

请教提取文本文件中某段内容的最快方法?

[复制链接]
发表于 2009-4-11 22:06:37 | 显示全部楼层 |阅读模式
我想要从文本文件中提取某段内容,我现在的实现方法要不断读取文件,运行速度很慢,请教有没有更快的算法。

我的思路是:逐行读取该文件,当那行内容等于某值时,记录下起始行号;再继续往下读取,当某行内容等于另一个值时,记录下终止行号;用循环从起始行号到终止行号再次读取该文件,不断累加行内容直到结束,再写入文件。代码如下(尚未完全实现):
$num = 1
$file = FileOpen("test.txt", 0)
While 1
        $line = FileReadLine($file, $num)
        If @error = -1 Then ExitLoop
        $num = $num + 1
        If $line = " ===================================" Then ExitLoop                ;查找内容是仅有值
Wend
While 1
        $line = $line & @CRLF & FileReadLine($file, $num)
        If @error = -1 Then ExitLoop
        $num = $num + 1
Wend
FileClose($file)
$filecon = $line
$file = FileOpen("test.txt", 1)
FileWrite($file, $filecon)
FileClose($file)


[ 本帖最后由 thackit 于 2009-4-12 15:31 编辑 ]
发表于 2009-4-11 22:54:01 | 显示全部楼层
第一次的时候全部读到数组里 在内存中使用就会快很多
发表于 2009-4-11 23:55:49 | 显示全部楼层
读一次,放个开始标志。读取内容扔进数组,等于结束行时退出循环。数组有内容时用_ArrayToString组合成文件内容,然后写入文件。
另外,如果你要写入的文件与读取文件不同,你可以同时打开2个文件,这边读那边写。这样做的好处是不需要通过数组,节约内存使用。

Local $File, $Line, $iFlag = 0, $aResult[1]

$File = FileOpen("test.txt", 0)
If $File = -1 Then Exit

While 1
        $Line = FileReadLine($File)
        If @error Then ExitLoop
        If $iFlag = 0 AND $Line = "开始行" Then $iFlag = 1
        If $iFlag = 0 Then ContinueLoop
        _ArrayAdd($aResult, $Line)
        If $Line = "结束行" Then ExitLoop
WEnd

FileClose($File)

If UBound($aResult) > 1 Then FileWrite("test.txt", _ArrayToString($aResult, @CRLF, 1))


[ 本帖最后由 sensel 于 2009-4-12 00:05 编辑 ]
发表于 2009-4-12 00:02:23 | 显示全部楼层
还有个方法是暴力型。把整个文件读入一个变量,再截取从开始行到结束行的字符串,然后写入文件。缺点是因为要读取整个文件,文件很大时速度太慢。
发表于 2009-4-12 00:18:37 | 显示全部楼层
与上面那段代码结果相同,但是经过速度优化。原因是_ArrayAdd操作用到了ReDim语句,但ReDim是很占CPU时间的。在我的机器上,当使用ReDim超过2000次时,可以明显感觉到速度下降。
这里参考新版的_FileListToArray,将ReDim操作减少为原来的1/1000来提升运行速度。缺点是代码稍稍复杂了一点。

Local $File, $Line, $iFlag = 0, $aResult[1]

$File = FileOpen("test.txt", 0)
If $File = -1 Then Exit

While 1
        $Line = FileReadLine($File)
        If @error Then ExitLoop
        If $iFlag = 0 AND $Line = "开始行" Then $iFlag = 1
        If $iFlag = 0 Then ContinueLoop

        $aResult[0] += 1
        If UBound($aResult) <= $aResult[0] Then ReDim $aResult[UBound($aResult) + 1000]
        $aResult[$aResult[0]] = $Line

        If $Line = "结束行" Then ExitLoop
WEnd

ReDim $aResult[$aResult[0] + 1]
FileClose($File)

If UBound($aResult) > 1 Then FileWrite("test.txt", _ArrayToString($aResult, @CRLF, 1))
 楼主| 发表于 2009-4-12 10:04:28 | 显示全部楼层
感谢 sensel 的帮助。

不过我用楼上的代码测试运行速度,只比顶楼的快一点点,顶楼2.7xxs vs 楼上2.6xxs。

我的目标是0.xxs

不知道正则表达式能不能快很多?
发表于 2009-4-12 10:52:59 | 显示全部楼层
要速度就把文件全部读入内存
$text=FileRead("test.txt")
$index1=StringInStr("开始字符串",$text)
$index2=StringInStr("结束字符串",$text)
$text1=StringMid($text,$index1,$index2-$index1)
FileWrite("text1.txt",$text1)
;$text1不包含结束字符串


[ 本帖最后由 cnsnc 于 2009-4-12 10:56 编辑 ]
发表于 2009-4-12 16:26:37 | 显示全部楼层
影响运行速度的关键在于磁盘读取速度和截取内容在文件中的位置、行数,大量的磁盘读操作必然带来运行速度下降。
暴力型的优点在于将文件一次读入到内存,相对来说可以提升一点速度。但缺点很明显,占用内存是整个文件大小,并且读取截取内容之后的行是多余操作,如果这类行数目很多反而拖慢了运行速度。

Local $File, $iPos

$File = FileRead("test.txt")
$iPos = StringInStr($File, "开始行")
$File = StringTrimLeft($File, $iPos)
$iPos = StringInStr($File, "结束行")
If $iPos <> 0 Then
        $iPos += StringLen("结束行")
        StringLeft($File, $iPos)
EndIf
FileWrite("test.txt", $File)
 楼主| 发表于 2009-4-12 16:56:42 | 显示全部楼层
还好文件最多一两百K,内存占用还能接受。多谢以上各位帮忙。
发表于 2009-4-12 21:04:11 | 显示全部楼层
参考:
$File = 文件内容 $a = 需要保留字符段前面的部分字符 $b = 需要保留字符段后面的部分字符
$STR = StringRegExp($File, '(?<=' & $a & ').+(?=' & $b, 2, 1)
您需要登录后才可以回帖 登录 | 加入

本版积分规则

QQ|手机版|小黑屋|AUTOIT CN ( 鲁ICP备19019924号-1 )谷歌 百度

GMT+8, 2025-1-12 23:10 , Processed in 0.079632 second(s), 20 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表