注册 登录
编程论坛 VB6论坛

求一段VB比较d盘的两个.txt文件并提取不同数据的代码

vbcaonia 发布于 2023-02-04 11:38, 2396 次点击
求一段VB比较d盘的两个.txt文件并提取不同数据的代码

附件按钮程序运行速度太慢,请帮我优化一下代码以达到提速的效果或换一种更高效的写法,谢谢  !!!

题意:

1、d盘有两个.txt文件分别为aaa.txt与bbb.txt,两个.txt文件内容格式是一行一个口令。
2、aaa.txt文件逐行在bbb.txt文件中查找对比,当aaa.txt文件某行不存在bbb.txt文件时则将aaa.txt文件中的这一行文本提取到list1。


只有本站会员才能查看附件,请 登录

18 回复
#2
风吹过b2023-02-04 12:40
你的代码,第一次运行时为 0.03秒,其他时间为 0秒,我的代码第一就是 0 秒。
数据量太小,重复100次测速,
我测试的结果是,你的代码 约0.6秒,我的代码 约 0.05秒,10倍的速度差异。
不过,你的代码我没看懂,主要不明白 scripting.dictionary 的用法。你的速度也主要慢在 引用 scripting.dictionary 上面。

另外,遍类二个数组查找的办法,我没去测试,感觉会比字符串直接查找要慢。

程序代码:
t = Timer
Dim i As Long, j As Long
Dim aa() As String, bb As String

  '打开对比数据
  Open "D:\VBUser\vb--txt对比\bbb.txt" For Input As #1
   '将txt文件内容赋值给数组bb,bb为整个文件内容,不分行
    bb = StrConv(InputB(LOF(1), 1), vbUnicode) '将文件号为1的文件的全部字符转换成国际标准化组织 (ISO) 字符标准后传送给aa
    Close #1
    bb = vbCrLf & bb & vbCrLf   '前后各加一个回车换行符,为后面直接查找创造条件

  '打开对比数据
  Open "D:\VBUser\vb--txt对比\aaa.txt" For Input As #1
   '将txt文件内容赋值给数组aa,aa的元素为txt的一行
    aa = Split(StrConv(InputB(LOF(1), 1), vbUnicode), vbCrLf) '将文件号为1的文件的全部字符转换成国际标准化组织 (ISO) 字符标准后传送给aa
    Close #1

    List1.Clear            '清列表
    For i = 0 To UBound(aa)
        If InStr(1, bb, vbCrLf & aa(i) & vbCrLfb) = 0 Then            'aa行前后加了回车换行符后在bb里直接查找。找不到则添加
            List1.AddItem aa(i)
        End If
    Next i
   
MsgBox "用时 " & Format(Timer - t, "0.00") & ""


[此贴子已经被作者于2023-2-4 12:50编辑过]

#3
vbcaonia2023-02-04 15:26
回复 2楼 风吹过b
版主你好,我实际用到的aaa与bbb二个txt文件的总行数分别在800万行左右,我的电脑每次要跑20分钟才有结果,先消化一下你的代码,谢谢!!!
#4
风吹过b2023-02-04 16:51
800万行,
那要注意读文件会不会报内存溢出,如果会,那要换读文件 和 内存数据保存方式。
还有 InStr(1, bb, vbCrLf & aa(i) & vbCrLfb) 这行会不会报错。如果这行报错,那要换 内存数据保存方式和 搜索方式,

继续优化,就是以内存换速度。
那再定义一个 数组 , 如 (浏览器写的代码,未经测试)
dim cc() as string
    redim cc(ubound(aa))
    for i=0 to ubound(aa)
        cc(i)=vbcrlf & aa(i) & vbcrlf    '因数据量超大,把需要查找的数据先组合好来,以空间换速度
    next i

    List1.Clear            '清列表
    For i = 0 To UBound(aa)
        If InStr(1, bb, cc(i)) = 0 Then            '使用aa前后加了回车换行符串在bb里直接查找,空间换速度。找不到则添加
            List1.AddItem aa(i)
        End If
    Next i
#5
风吹过b2023-02-04 17:17
我的方法原理:

总表中保存在内存中,是一个字符串,格式是这个
0D 0A 每行的数据 0D 0A 。。。。。。。 0D 0A
0D0A 回车换行符,对应的常量是: vbcrlf 第一个和最后一个是我们手动添加的。
在 0D0A之间就是每行的数据,
然后 需要查找到的字符,我们加上了 VBcrlf,
0D 0A 每行的数据 0D 0A
查找时,就会匹配到 每行的数据及它的两头的分隔符(VBCRLF)
为什么两头都要加上这个符号呢?防止匹配到不完整的行。如果你数据每行都是等长的,那也可以不再附加分隔符。




#6
vbcaonia2023-02-04 19:29
回复 5楼 风吹过b
版主你好,我数据加大到各3万行,用你的方法时间是22秒,用附件中的字典法用时1秒(vb6.0、excel都测了),所以方法有待改进,能在程序中增加某个自定义函数可能会快很多,谢谢!

[此贴子已经被作者于2023-2-4 19:31编辑过]

#7
风吹过b2023-02-04 20:03
VB6本来就不适用于处理大数据量,主要是语言效率问题,最快的就是汇编、C(C++)。
你附件的字典法,引用的是对象,如果一次引用,多次使用。当使用次数超过一定时,就会把因引用对象所消耗的时间补回来。

如你的时间分配:引用对象,可能 是 0.599秒,然后使用只需要 0.00001秒,我测试时也发现这种情况,首次运行时与第二次运行相比,第二次运行时间总是为0,说明时间主要消耗在引用上面。
当数据量一大,引用所花费的时间不变,但使用时间基数极小,成倍增长也不会发生很大的变化。而我写的代码,每次运行的时间比你的时间要长,成倍增长后这个时间就会增长非常多,最终远远超过你的最终时间。

所以大数据量的处理办法,一是改用 C(C++)写,二是使用 C(C++)开发的组件。
而你这个字典就是第二种情况。纯VB6代码,无法在大数据量上的运行速度打败你的方法。
VB6的优点在于 开发简单些的程序  和 小数据量处理 。

#8
vbcaonia2023-02-04 23:18
回复 7楼 风吹过b
谢谢!!!
#9
冬瓜汤2023-02-05 12:53
800万行,除了数据库,你有更好的选择吗?这是工具选择的问题,跟编程语言关联并没有那么大。
我见过另一个人是 2亿行的文本 ,和你一样是匹对。文件大小 20几G,有得选吗?除了数据库,几乎没有更好的选择。
#10
风吹过b2023-02-05 14:07
数据库引擎 也是 C/C++ 写的。也是符合我说的第二种情况。
语言还是有关系的,但语言之间可以互相引用组件的,从而减少语言之间的差距。

C语言离硬件非常近,仅次于汇编,但汇编太难学了。所以现在 操作系统级的东西,基本都是 C/C++写的,实在不行,还要在 C/C++ 里内嵌汇编。为啥,离硬件近,效率高。
高级语言为啥高级,因为提供了更好的界面,提供了更多方便的函数。然后这些都是有代价,代价就是编译后的代码运行效率低。
如 i++ ,在C/C++ 里经常用的代码
编译后就是三行汇编,多简洁
mov eax,dword prt[i]
add eax ,1
mov dword ptr[i],eax

vb6里又是怎么样的呢
i=i+1
编译后是什么呢?如果I未定义数据类型,那就是 Variant  
VB6运行时 先判断数据类型,然后不是数据的转化为数据类型,然后再根据数据类型,再决定是生成 add 指令,还是 fadd
这步数就多的去了,速度怎么提得起来。
参看 https://bbs.bccn.net/viewthread.php?tid=510977 四楼的反汇编分析。


#11
vbcaonia2023-02-05 16:34
回复 9楼 冬瓜汤
用grep和awk,不重复的800万找800万也只要7秒


[此贴子已经被作者于2023-2-5 16:39编辑过]

#12
vbcaonia2023-02-05 18:25
回复 10楼 风吹过b
谢谢版主!!!

另外请教一下access数据库txt数据导入问题:
F盘有access数据库:数据条件源.mdb,仅有一个字段:表1,用下面程序将txt文件逐行写入到表1各记录,速度很慢,请版主提提速度!



Private Sub Command9_Click()
Dim log1 As String
Dim Con As New adodb.Connection
Dim Rs As New adodb.Recordset

Con.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=F:\数据条件源.mdb;Persist Security Info=False"
 Con.Open '打开数据库
Con.Execute ("delete from 表1") '清空表1
CommonDialog1.ShowOpen '打开对话框
t = CommonDialog1.FileName '获取文件名
Open t For Input As #1 '打开文件并读入
Do While Not EOF(1) '表示1号文件没有尾部
Input #1, log1
Con.Execute ("insert into 表1 values( '" & log1 & "')")
Loop
Close #1
ErrHandler: '

Exit Sub
End Sub
#13
mrexcel2023-02-06 08:37
以下是引用vbcaonia在2023-2-5 18:25:45的发言:

谢谢版主!!!

另外请教一下access数据库txt数据导入问题:
F盘有access数据库:数据条件源.mdb,仅有一个字段:表1,用下面程序将txt文件逐行写入到表1各记录,速度很慢,请版主提提速度!



Private Sub Command9_Click()
Dim log1 As String
Dim Con As New adodb.Connection
Dim Rs As New adodb.Recordset

Con.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=F:\数据条件源.mdb;Persist Security Info=False"
 Con.Open '打开数据库
Con.Execute ("delete from 表1") '清空表1
CommonDialog1.ShowOpen '打开对话框
t = CommonDialog1.FileName '获取文件名
Open t For Input As #1 '打开文件并读入
Do While Not EOF(1) '表示1号文件没有尾部
Input #1, log1
Con.Execute ("insert into 表1 values( '" & log1 & "')")
Loop
Close #1
ErrHandler: '

Exit Sub
End Sub


试试把文本文件直接作为数据源整体导入, "INSERT INTO 表1 SELECT * " _
        & "FROM [data.txt] IN '" & path & " where ..."
#14
vbcaonia2023-02-06 10:23
回复 13楼 mrexcel
版主你好我写了一下没成功,麻烦你在附件按钮2中写段代码,谢谢!


F盘有access数据库:数据条件源,在电脑中选择.txt文本导入到表1的数据字段中其结果如附件“导入数据按钮”。


只有本站会员才能查看附件,请 登录
只有本站会员才能查看附件,请 登录
#15
mrexcel2023-02-06 11:49
程序代码:
Private Sub 表1导入数据()
Dim Con As New ADODB.Connection
With Con
.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=F:\数据条件源.mdb;Persist Security Info=False"
.Open '打开数据库
.Execute ("insert into 表1  SELECT * FROM [text;HDR=no;Database=F:\].[DATA.txt];")
End With
End Sub

测试通过
#16
吹水佬2023-02-06 13:58
也可以直接将TXT的文件夹当作“数据库”,TXT当作数据表,但这效率并不一定会有大提高。
只有本站会员才能查看附件,请 登录

程序代码:

Sub Main()
    Dim con
    Set con = CreateObject("ADODB.Connection")
    con.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Extended Properties='text;HDR=NO';Data Source=D:\temp\test\vb-数据导入\"
    con.Open
    Dim rec, field
    Set rec = CreateObject("ADODB.Recordset")
    rec.Open "SELECT * FROM aaa.txt", con, 1, 3, 1
    rec.MoveFirst
    Do While Not rec.EOF()
        For Each field In rec.fields
            Debug.Print field.Value
        Next
        rec.MoveNext
    Loop
    rec.Close
    con.Close
End Sub
#17
吹水佬2023-02-06 14:06
以“行串”比对,先按“行串”排序,这样用两个文件“行串”指针同时扫描一次两个文件,比对“行串”就可以得到结果。
#18
vbcaonia2023-02-06 15:35
回复 15楼 mrexcel
版主你好,我弄来弄去就是不成功,提示包含没知字段名或者是找不到[DAFA.TXT],你试一下我发的附件数据能否导入,谢谢!

只有本站会员才能查看附件,请 登录




[此贴子已经被作者于2023-2-6 19:00编辑过]

#19
vbcaonia2024-02-19 23:08
回复 15楼 mrexcel
老师你好,请问这个程序为啥我这里要双击按钮才出数据呀(不双击没有数据显示),谢谢!

[此贴子已经被作者于2024-2-19 23:11编辑过]

1