cumtljj 发表于 2014-5-24 18:50:10

对比两个文本时用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

文本模式如下

gto250 发表于 2014-5-24 22:41:50

自己的机子上用时四分钟,期待高手

;~ ;================================生成
;~ 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)&"秒")

cumtljj 发表于 2014-5-24 22:52:54

回复 2# gto250


   你的那个需要对比的文件多少行啊

gto250 发表于 2014-5-24 23:02:53

5W呀,上面注释掉的就是生成文件的

cumtljj 发表于 2014-5-24 23:04:03

回复 2# gto250


    你好 我想问下 你用的是“FileReadToArray”还 是“_FileReadToArray” 我的怎么只有后面的那个啊

cumtljj 发表于 2014-5-24 23:07:18

回复 4# gto250


    你好 我想问下 你用的是“FileReadToArray”还 是“_FileReadToArray” 我的怎么只有后面的那个啊

gto250 发表于 2014-5-25 00:59:41

v3.3.11.3 (Beta)
有FileReadToArray这个函数,而且在_FileReadToArray中最后调用的也还是FileReadToArray这个函数

我本来想用易语言给你编写个dll的,那个速度快,只要几秒时间,但是我不知道怎么把数据从dll中传递到au3中,可能数据太大了或者是其他原因,因为我也不怎么会易语言

kevinch 发表于 2014-5-25 07:47:12

#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可以根据需要进行调整

gto250 发表于 2014-5-25 08:18:30

用易语言编了个dll,比au3速度快多了。

gto250 发表于 2014-5-25 08:21:23

不知道附件要不要收费的,还是附源码吧。
$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)

auto 发表于 2014-5-25 08:28:05

回复 10# gto250


   搞易语言交流区好了

cumtljj 发表于 2014-5-25 09:33:11

回复 10# gto250


    谢谢了 搞的我都想学易语言了……

cumtljj 发表于 2014-5-25 09:39:43

回复 8# kevinch


    谢谢了

cumtljj 发表于 2014-5-25 10:10:53

回复 9# gto250


    还有一个问题想麻烦下你能帮我解释解释你写的dll中的bj这个函数的具体含义还有其参数的意义么?dll我也就只懂一点点 能麻烦你注释下么?谢谢

gto250 发表于 2014-5-25 10:51:32

一共三个参数
前两个是文本型的
第一个参数是第一个文件路径
第二个参数是第二个文件路径
第三个是整数型的
第一次调用的时候,设置类型为整数,0
返回值就是返回的文本长度
第二次调用的时候,设置一个同等长度的数据结构,设置为指针
返回的就是该指针地址的内存内容
页: [1] 2
查看完整版本: 对比两个文本时用FileReadLine读取数据后逐行比较 如何提高效率?