对比两个文本时用FileReadLine读取数据后逐行比较 如何提高效率?
本帖最后由 cumtljj 于 2014-5-24 18:51 编辑自己想写一段代码 来对比两个文本的数据 根据数据的特点可以使用逐行读取对比的方法 写好了后运行发现效率太低了 我的文件有5万多行呢 三四十分钟都对比不完啊?
各位高手有没有什么高效率的方法呢?
我的源码如下#NoTrayIcon
#Region ;**** 参数创建于 ACNWrapper_GUI ****
#PRE_Icon=..\icon图标.ico
#PRE_Res_requestedExecutionLevel=None
#EndRegion ;**** 参数创建于 ACNWrapper_GUI ****
#include <array.au3>
#include <file.au3>
#include <CoProc.au3> ;多进程udf
#include <ButtonConstants.au3>
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#Include <GuiToolBar.au3>
#Region ### START Koda GUI section ###
$Form1 = GUICreate("小鹤码表比对器", 380, 220,492, 124)
$Label1 = GUICtrlCreateLabel("请选择旧码表:", 16, 16, 116, 24)
GUICtrlSetFont(-1, 9, 400, 0, "MS Sans Serif")
$Input1 = GUICtrlCreateInput("", 64, 40, 233, 25)
$Button1 = GUICtrlCreateButton("选择文件", 304, 40, 57, 25)
$Input2 = GUICtrlCreateInput("", 64, 112, 233, 25)
$Button2 = GUICtrlCreateButton("选择文件", 304, 112, 57, 25)
$Button3 = GUICtrlCreateButton("开始比较", 72, 152, 225, 41)
$Label2 = GUICtrlCreateLabel("请选择新码表:", 16, 85, 116, 24)
GUICtrlSetFont(-1, 9, 400, 0, "MS Sans Serif")
$Label3 = GUICtrlCreateLabel("已比对0行数据", 95, 200, 300, 20)
GUICtrlSetFont(-1, 10, 400, 0, "MS Sans Serif")
$Label4 = GUICtrlCreateLabel("", 346, 200, 100, 20)
GUICtrlSetFont(-1, 10, 400, 0, "MS Sans Serif")
GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###
TraySetState();只显示主进程图标
While 1
$nMsg = GUIGetMsg()
Switch $nMsg
Case $GUI_EVENT_CLOSE
Exit
Case $Button1
Local $file1=FileOpenDialog("请选择文件",@DesktopDir,"文本文件 (*.txt)" )
If @error Then
MsgBox(0,"","请重新选择!")
Else
GUICtrlSetData($Input1,$file1)
EndIf
Case $Button2
Local $file2=FileOpenDialog("请选择文件",@DesktopDir,"文本文件 (*.txt)" )
If @error Then
MsgBox(0,"","请重新选择!")
Else
GUICtrlSetData($Input2,$file2)
EndIf
Case $Button3
Local $pd1=GUICtrlRead($input1),$pd2=GUICtrlRead($input2)
If $pd1<>"" And $pd2<>"" Then
Global $pidmain=_CoProc("main",$Form1&"|"&$pd1&"|"&$pd2&"|"&$Label3&"|"&$Label4);调用主进程变量的方法
Global $pidtime=_CoProc("time",$Form1&"|"&$Label4)
_CloseHandle($pidmain)
_CloseHandle($pidtime)
Else
MsgBox(0,"提示","请选择文件!")
EndIf
EndSwitch
WEnd
Func main($sParam)
;MsgBox(0,"",$sParam)
$aParam = StringSplit($sParam, "|")
$hWnd = HWnd($aParam)
Local $txt1=FileOpen($aParam)
Local $txt2=FileOpen($aParam)
Local $num,$a=1
Local $array[$a];存放对比数据
Local $readline1=_FileCountLines($aParam)
Local $readline2=_FileCountLines($aParam)
If $readline1 > $readline2 Then
Local $count=$readline1
Else
$count=$readline2
EndIf
For $num=1 To $count
Local $line1,$line2
$line1=FileReadLine($txt1,$num)
$line2=FileReadLine($txt2,$num)
If $line1<>$line2 Then
ReDim $array[$a]
$array[$a-1]=$line1
$array[$a-1]=$line2
$a+=1
EndIf
If Mod($num,1000)=0 Then
ControlSetText($hWnd, '', Number($aParam),"共"&$count&"行,"&"已比对"&$num&"行数据")
EndIf
If $num=$count Then
ControlHide($hWnd,"",Number($aParam))
EndIf
Next
FileClose($txt1)
FileClose($txt2)
_ArrayDisplay($array)
EndFunc
Func time($time)
$time = StringSplit($time, "|")
$n1 =Number($time) ;$input1 的控件id
$hWnd1 = HWnd($time)
Local $fen,$sed,$min=0
While $sed>=0
$sed+=1
If $sed=60 Then
$sed=0
$min+=1
EndIf
If $min<10 Then
$fen="0"&$min
Else
$fen=$min
EndIf
If $sed<10 Then $sed="0"&$sed
ControlSetText($hWnd1, '', Number($time),$fen&":"&$sed)
Sleep(1000)
WEnd
EndFunc
文本模式如下
自己的机子上用时四分钟,期待高手
;~ ;================================生成
;~ Dim $str
;~ $f1=@ScriptDir&"\1.txt"
;~ $f2=@ScriptDir&"\2.txt"
;~ $fh1=FileOpen($f1,10)
;~ $fh2=FileOpen($f2,10)
;~ For $i=1 To 50000
;~ $str=$str&"123456789"&@CRLF
;~ Next
;~ FileWrite($fh1,$str)
;~ FileWrite($fh2,StringReplace($str,"234","111"))
;~ FileClose($fh1)
;~ FileClose($fh2)
;~ ;=================================
$t=TimerInit()
Dim $str
$f1=@ScriptDir&"\1.txt"
$f2=@ScriptDir&"\2.txt"
$str1=FileReadToArray($f1)
$str2=FileReadToArray($f2)
For $i = 0 To UBound($str1) - 1
If $str1[$i] <> $str2[$i] Then
$str=$str&$str1[$i]&@TAB&$str2[$i]&@TAB&"序"&$i+1&@CRLF
EndIf
Next
FileWrite("3.txt",$str)
$time=TimerDiff($t)
MsgBox(0,"","用时"&Round($time/1000,2)&"秒") 回复 2# gto250
你的那个需要对比的文件多少行啊 5W呀,上面注释掉的就是生成文件的 回复 2# gto250
你好 我想问下 你用的是“FileReadToArray”还 是“_FileReadToArray” 我的怎么只有后面的那个啊 回复 4# gto250
你好 我想问下 你用的是“FileReadToArray”还 是“_FileReadToArray” 我的怎么只有后面的那个啊 v3.3.11.3 (Beta)
有FileReadToArray这个函数,而且在_FileReadToArray中最后调用的也还是FileReadToArray这个函数
我本来想用易语言给你编写个dll的,那个速度快,只要几秒时间,但是我不知道怎么把数据从dll中传递到au3中,可能数据太大了或者是其他原因,因为我也不怎么会易语言 #include <file.au3>
;~ ;================================生成
;~ Dim $str
;~ $f1=@ScriptDir&"\1.txt"
;~ $f2=@ScriptDir&"\2.txt"
;~ $fh1=FileOpen($f1,10)
;~ $fh2=FileOpen($f2,10)
;~ For $i=1 To 50000
;~ $str=$str&"123456789"&@CRLF
;~ Next
;~ FileWrite($fh1,$str)
;~ FileWrite($fh2,StringReplace($str,"234","111"))
;~ FileClose($fh1)
;~ FileClose($fh2)
;~ ;=================================
$t=TimerInit()
Dim $str
$f1=@ScriptDir&"\1.txt"
$f2=@ScriptDir&"\2.txt"
$f3=@ScriptDir&"\3.txt"
Dim $str1,$str2
_FileReadToArray($f1,$str1)
_FileReadToArray($f2,$str2)
FileDelete($f3)
$target=FileOpen($f3,1)
$str=""
For $i = 0 To UBound($str1) - 1
If $str1[$i] <> $str2[$i] Then
$str=$str&$str1[$i]&@TAB&$str2[$i]&@TAB&"序"&$i+1&@CRLF
If StringLen($str)>2048 Then
FileWriteLine($target,$str)
$str=""
EndIf
EndIf
Next
If $str<>"" Then FileWriteLine($target,$str)
FileClose($target)
$time=TimerDiff($t)
MsgBox(0,"","用时"&Round($time/1000,2)&"秒")借用gto的代码,可能出在超长字符串的串接上,浪费了太多时间,可以利用缓冲试一下,结果没测试对不对,那个2048可以根据需要进行调整 用易语言编了个dll,比au3速度快多了。
不知道附件要不要收费的,还是附源码吧。
$f1=@ScriptDir&"\1.txt"
$f2=@ScriptDir&"\2.txt"
$a=DllCall("123.dll","int","bj","str",$f1,"str",$f1,"int",0)
$b=DllStructCreate("char["&$a&"]")
$p=DllStructGetPtr($b)
$c=DllCall("123.dll","int","bj","str",$f1,"str",$f1,"ptr",$p)
FileWrite("3.txt",DllStructGetData($b,1))
.版本 2
.支持库 commobj
.程序集 程序集1
.程序集变量 k1, 快速文本对象
.程序集变量 k2, 快速文本对象
.程序集变量 k3, 快速文本对象
.子程序 _启动子程序, 整数型, , 请在本子程序中放置动态链接库初始化代码
_临时子程序 ()' 在初始化代码执行完毕后调用测试代码
返回 (0)' 返回值被忽略。
.子程序 _临时子程序
' 本名称子程序用作测试程序用,仅在开发及调试环境中有效,编译发布程序前将被系统自动清空,请将所有用作测试的临时代码放在本子程序中。 ***注意不要修改本子程序的名称、参数及返回值类型。
.子程序 bj, 整数型, 公开
.参数 文件1, 文本型
.参数 文件2, 文本型
.参数 文件3, 整数型
.局部变量 str1, 文本型, , "0"
.局部变量 str2, 文本型, , "0"
.局部变量 n1, 整数型
.局部变量 n, 整数型
.局部变量 fstr, 文本型
.局部变量 临时地址, 整数型
k1.从文件读 (文件1)
k2.从文件读 (文件2)
str1 = k1.分割文本 (#换行符, )
str2 = k2.分割文本 (#换行符, )
n1 = 取数组成员数 (str1)
.变量循环首 (1, n1, 1, n)
.如果 (str1 ≠ str2 )
.否则
k3.添加 (str1 + 字符 (9) + str2 + 字符 (9) + “序号” + 到文本 (n) + 字符 (13))
.如果结束
.变量循环尾 ()
fstr = k3.取文本 (, )
.如果 (文件3 = 0)
返回 (k3.取长度 ())
.否则
写到内存 (fstr, 文件3, k3.取长度 ())
.如果结束
返回 (0) 回复 10# gto250
搞易语言交流区好了 回复 10# gto250
谢谢了 搞的我都想学易语言了…… 回复 8# kevinch
谢谢了 回复 9# gto250
还有一个问题想麻烦下你能帮我解释解释你写的dll中的bj这个函数的具体含义还有其参数的意义么?dll我也就只懂一点点 能麻烦你注释下么?谢谢 一共三个参数
前两个是文本型的
第一个参数是第一个文件路径
第二个参数是第二个文件路径
第三个是整数型的
第一次调用的时候,设置类型为整数,0
返回值就是返回的文本长度
第二次调用的时候,设置一个同等长度的数据结构,设置为指针
返回的就是该指针地址的内存内容
页:
[1]
2