找回密码
 加入
搜索
查看: 9739|回复: 24

[效率算法] [已解决]大量文本约250w行如何短时间快速整理每30行保留一行数据?

 火.. [复制链接]
发表于 2012-7-4 09:06:10 | 显示全部楼层 |阅读模式
本帖最后由 user11 于 2012-7-5 09:47 编辑

最近做试验,结果设置参数的时候欠缺考虑,设置数据采集时间为1s一次,试验进行了一个月结束,麻烦来了

由于采样时间太短,生成的数据大约有259W行,文本太大有二三百兆没法处理了,

excel origin 打开就死掉,其实30s取样一次就可以了,自己用AU3写了个程序,精简数据。

前7行是固定格式的文件头,不需要精简,第八行以后是数据文本,每30行保留一行即可,

但是这个处理速度太慢,已经5、6个小时了还没搞定一个数据,求助如何提高效率~~


非常感谢A版,问题完美解决,正则太神奇了,方法看楼下A版的神作!!实例22楼!

回复的朋友,非常感谢你们的想法和意见!!tryhi、lixiaolong的正则应该也可以用,

但是A版真是细心,给了直接可以用的,改都不用改,Qokelate考虑的确很周全!



#include <File.au3>
Dim $i=1
$aFile = FileOpenDialog("快速精简行",@ScriptDir&"\","文本文件 (*.txt;*.dic)", 1 + 4)
If @error Then 
        MsgBox(0,0,"文件未选择",3)
        Exit
EndIf

$file=FileOpen($aFile)

        $out_file=StringTrimRight($aFile,4)&'_已完成.txt'
        if FileExists($out_file) then FileDelete($out_file)
        FileOpen ($out_file,2)

While 1
    $line = FileReadLine ($file,$i)        
        If @error = -1 Then ExitLoop        
TrayTip("正在处理","行:"&$i,2,1)
FileWriteLine($out_file, $line)

if $i<7 then
$i=$i+1
else        
$i=$i+30
endif

WEnd

发表于 2012-7-4 10:00:23 | 显示全部楼层
打开/编辑超大文件(G级)的,是很大的课题的

不过你的文件还不算大,不过建议你用一些现成的Editor干这种事,如专门对超大文件有优化的EmEditor,UE等。它们都会自动判断硬件资源和部分读文件入内存处理,而不是全部读文件入内存的。

可惜的是au3不能支持Hash表,不然做这种事要快很多很多。也只好用Assign,Eval ,IsDeclared这种表驱动方式来模拟Hash表。

评分

参与人数 1金钱 +10 收起 理由
user3000 + 10 good idea

查看全部评分

 楼主| 发表于 2012-7-4 11:22:13 | 显示全部楼层
UE之类我当然知道,,关键我要精简一下数据,,不会正则,UE不熟悉,不只能能不能按行精简下来
发表于 2012-7-4 12:03:04 | 显示全部楼层
回复 3# user11


    就是不用这些,你在用FileReadLine之前,先用FileSetPo或_WinAPI_SetFilePointer效率也应该提高好多
发表于 2012-7-4 12:49:32 | 显示全部楼层
回复 4# happytc
印象里filesetpos好像不支持行,忘了
发表于 2012-7-4 13:03:17 | 显示全部楼层
用正则吧,应该就是几秒钟的事,现在没时间,晚上来试下~
发表于 2012-7-4 14:00:54 | 显示全部楼层
回复 5# netegg


    对,肯定不能直接支持了,au3里所有默认的所谓‘行’的操作,其在用C++写的时候,其实也就是搜@LF后,得到偏移量(OffSet)后移动指针而已。
 楼主| 发表于 2012-7-4 15:17:20 | 显示全部楼层
回复 6# afan

正则可以几秒钟,,这个厉害,,不懂正则,这个很需要,,期待  A版 的大作!
发表于 2012-7-4 17:31:32 | 显示全部楼层
本帖最后由 tryhi 于 2012-7-4 17:32 编辑
### 友情提示:本脚本由 Au3.REHelper 于 2012/07/04 17:28 自动生成,不保证其正确性,请自行测试 ###
#include <Array.au3>
Local $Str = _
                '1行' & @CRLF & _
                '2行' & @CRLF & _
                '3行' & @CRLF & _
                '4行' & @CRLF & _
                '5行' & @CRLF & _
                '6行' & @CRLF & _
                '7行' & @CRLF & _
                '8行' & @CRLF & _
                '9行' & @CRLF & _
                '10行' & @CRLF & _
                '11行' & @CRLF & _
                '12行' & @CRLF & _
                '13行' & @CRLF & _
                '14行' & @CRLF & _
                '15行' & @CRLF & _
                '16行' & @CRLF & _
                '17行' & @CRLF & _
                '18行' & @CRLF & _
                '19行' & @CRLF & _
                '20行' & @CRLF & _
                '21行' & @CRLF & _
                '22行' & @CRLF & _
                '23行' & @CRLF & _
                '24行' & @CRLF & _
                '25行' & @CRLF & _
                '26行' & @CRLF & _
                '27行' & @CRLF & _
                '28行' & @CRLF & _
                '29行'
MsgBox(0, '原字符串', $Str)
Local $Test = StringRegExp($str, '.*?\v+.*?\v+.*?\v+.*?\v+.*?\v+.*?\v+.*?\v+.*?\v+.*?\v+.*?\v+.*?\v+.*?\v+.*?\v+.*?\v+.*?\v+.*?\v+.*?\v+.*?\v+.*?\v+.*?\v+.*?\v+.*?\v+.*?\v+.*?\v+.*?\v+.*?\v+.*?\v+.*?\v+.*?\v+(.*?)\v+.*?', 3)
If Not @Error Then MsgBox(0, '匹配数量: ' & UBound($Test), '其中[0]元素为: ' & $Test[0])
_ArrayDisplay($Test, UBound($Test))
献丑写一条烂到鬼的正则,楼主可拿去测试一下,每30行提取一个1行(测试的时候不是每30行,所以上面的字符串没那么长)


坐等A版表演
发表于 2012-7-4 19:35:07 | 显示全部楼层
回复 9# tryhi

正则可以这么写.

#include <Array.au3>

Local $Str

For $i = 1 To 30000
        $Str &= $i & "行" &  @CRLF
Next

Local $Test = StringRegExp($Str, '(?m)(^.*?\v){30}', 3)
_ArrayDisplay($Test, UBound($Test))
发表于 2012-7-4 20:00:04 | 显示全部楼层
坐等Afan大大的表演,表示好奇!
发表于 2012-7-4 20:43:18 | 显示全部楼层
98万多行,本机测试 5xx 毫秒
Local $File_test = '98万行测试样本.txt', $File_New = '测试输出.txt'
If Not FileExists($File_test) Then
        Local $sHead = '', $sData = ''
        For $i = 1 To 7
                $sHead &= '固定格式的文件头第' & $i & '行' & @CRLF
        Next
        Local $sData = '需保留行1' & @CRLF
        For $i = 2 To 30
                $sData &= '需删除行' & $i & @CRLF
        Next
        For $i = 1 To 15
                $sData &= $sData
        Next
        ;结尾添加一些行,因为不大可能数据总行数都是30的倍数
        $sData &= '需保留行1------标记最后提取行' & @CRLF
        For $i = 2 To 18
                $sData &= '需删除行' & $i & @CRLF
        Next
        $sData &= '数据完毕'
        FileWrite($File_test, $sHead & $sData)
        Msgbox(0, 0, '已创建 983,066 行测试数据')
EndIf

;==================== 开始测试
Local $str = FileRead($File_test)
Local $ts = TimerInIt()
Local $sRP = StringRegExpRePlace($str, '^((?:\V*\v+){8})(?:\V*\v+){29}|(\V*\v+)(?:\V*\v+){29}', '\1\2')
FileDelete($File_New)
FileWrite($File_New, $sRP)
Msgbox(0, 0, '完成耗时:' & Round(TimerDiff($ts)) & ' ms')

评分

参与人数 1金钱 +18 收起 理由
user3000 + 18 cool~!

查看全部评分

发表于 2012-7-4 20:48:57 | 显示全部楼层
测试 400万 行,2 秒多
发表于 2012-7-4 22:14:13 | 显示全部楼层
这个要学习。
发表于 2012-7-4 22:53:53 | 显示全部楼层
回复 12# afan


    FileRead 会将整个文件读入内存,如楼主所说,如果文件是200M,内存占用将达200M
您需要登录后才可以回帖 登录 | 加入

本版积分规则

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

GMT+8, 2024-5-14 02:58 , Processed in 0.095443 second(s), 28 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

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