vb大数据处理技术问题

no000on 2014-07-02 01:58:33
我在前面提过这个问题
问题描述,从一个TXT文件取出所有身份证号码,身份证号码所在分割位置不一定

txt文件内容格式如下
"0100000000002013030003","姓名","","1","1963/10/13","1963/10/13","37062019631013301X","110108","地址地址在地址地址地址","110108",
"0201000009992012060001","姓名","","","1","1978/01/08","1978/01/08","120104197801086036","110106","地址地址在地址地址地址","11",
"1105280009992006030003",,"姓名","1","1978/01/08","1978/01/08","41280119770827231X","110106","地址地址在地址地址地址","11",
"1105280009992006030002",,"姓名","1","1978/01/08","1978/01/08","350181197808116571","110106","地址地址在地址地址地址","11",
"1105280009992006060011",,"姓名","1","1978/01/08","1978/01/08","350181198306105877","110106","地址地址在地址地址地址","11",
"1105280009992006060012",,"姓名","","","1","1978/01/08","1978/01/08","42070319840510277X","110106","地址地址在地址地址地址","11",
"1105280009992006090015",,"姓名","","","1","1978/01/08","1978/01/08","341623198605018311","110106","地址地址在地址地址地址","11",
"1105280009992006110018",,"姓名","1","1978/01/08","1978/01/08","410305690215031","110106","地址地址在地址地址地址","11",
"1105280009992006120019",,"姓名","1","1978/01/08","1978/01/08","410527700303295","110106","地址地址在地址地址地址","11",
.........
一行一条数据,总共有将近50W行数据,文件大小在14M多
身份证号码有15位 18位(虽然有逗号分隔,但是号码位置不固定的,分隔截取是完全拿不到的)
我用普通方式来逐行读取数据,用正则表达式可以提出号码,但是整个过执行完差不多在400秒

最后找到相关资料看到 内存映射 相关的技术,处理大文件比较快
对于这块资料网上基本都是介绍函数的时候没有具体的实例
也不知道用内存映射方式来出来这个文件效果如何?或者有其他什么方法
...全文
527 22 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
no000on 2014-07-06
  • 打赏
  • 举报
回复
引用 21 楼 Chen8013 的回复:
应该是不必用正则。 你在19楼说的“没规律”那种, ①是不是每行只有一个身份证号码? ②是不是每行一定有身份证号码? 你还是可以发一个样本文档,给我看看。 记住把文件压缩后再发。 ^_^
我先结贴,另外开一个帖子
舉杯邀明月 2014-07-06
  • 打赏
  • 举报
回复
应该是不必用正则。

你在19楼说的“没规律”那种,
①是不是每行只有一个身份证号码?
②是不是每行一定有身份证号码?
你还是可以发一个样本文档,给我看看。
记住把文件压缩后再发。 ^_^
no000on 2014-07-05
  • 打赏
  • 举报
回复
我的帖子只能加到100分
no000on 2014-07-05
  • 打赏
  • 举报
回复
如果处理固定格式的文件速率真的比正则表达式快很多 以前很少接触文件处理的业务 这两天通过这些高人的热心指点学了不少东西 上述方法只能处理固定数据格式 如果格式不固定是不是又该返回用正则表达式了 例如如下格式: "0100000000002013030003","姓名","","1","1963/10/13","1963/10/13","37062019631013301X","110108","地址地址在地址地址地址","110108", "120104197801086036","0201000009992012060001","姓名","","","1","1978/01/08","1978/01/08","110106","地址地址在地址地址地址","11", 37062019631013301X 110103197912110686,372924197403010316 511111196803261013 510321197711148336 41272219700612874X 文件格式没有一定规律,这样的话是不是得通过正则表达式来?
no000on 2014-07-05
  • 打赏
  • 举报
回复
引用 15 楼 Chen8013 的回复:
Option Explicit

Private Sub Command1_Click()
   Const SEPSTR   As String = ""","""
      Dim strRlt() As String
      Dim strTemp As String
      Dim dTime   As Double
      Dim lNum    As Long
      Dim iFn     As Integer
      Dim i&, p&, ps&, pe&

   iFn = FreeFile()
   dTime = Timer()
   Open "E:\Tools\2.txt" For Input As #iFn
   Line Input #iFn, strTemp
   lNum = LOF(iFn) / Seek(iFn)
   ReDim strRlt(lNum)
   p = -1&: Seek iFn, 1
   Do
      If (EOF(iFn)) Then Exit Do
      p = p + 1&
      If (p > lNum) Then
         lNum = lNum + 160
         ReDim Preserve strRlt(lNum)
      End If
      Line Input #iFn, strTemp
      i = InStr(20, strTemp, "/")
      ps = InStr(i + 12, strTemp, SEPSTR) + 3
      pe = InStr(ps, strTemp, SEPSTR)
      strRlt(p) = Mid$(strTemp, ps, pe - ps)
   Loop
   Close
   Me.Print "耗时:" & Format$(Timer() - dTime, "0.00秒")
   Me.Print "提取数据:" & p + 1
   ' 结果检查:
   pe = -1&
   For i = 0 To p
      ps = Len(strRlt(i))
      If (ps <> 15& And ps <> 18&) Then
         Me.Print i + 1; "出错"
         pe = 0
      End If
   Next
   If (pe) Then Me.Print "数据检验合格。"
End Sub
楼主提供给我的样本文件 3.83MB,共15456条数据, 我复制5倍, 共19.1MB、77280条数据。 在我的一台配置比较差的办公电脑上,全部处理完仅1秒钟。 单读取文件,约0.9秒。
这个确实牛X,20W行数据测试2秒完成
引用 9 楼 Tiger_Zhao 的回复:
1)读文件不无需优化 (这个比较符合我的预期,系统和硬盘都有缓存,就算一个个字符读也不应该慢的,5楼那种“快很多”的情况前提不明确。) 2)输出优化 自己做个类似 StringBuilder 的拼字符串功能,文本框只需赋值一次。 3)解析优化 a.正则需要看具体代码了 b.个人感觉这种特定规则的自己查找应该比正则快
Function GetID(sLine As String) As String
    Dim lLength     As Long
    Dim i1          As Long    '字段开始位置
    Dim i2          As Long    '字段结束的逗号位置
    Dim s           As String

    lLength = Len(sLine)
    If lLength = 0 Then Exit Function

    i1 = 1
    While i1 <= lLength
        i2 = InStr(i1, sLine, ",")
        If i2 = 0 Then i2 = lLength + 1

        If (i2 - i1) <= 2 Then GoTo NextField
        If Mid$(sLine, i1, 1) <> """" Then GoTo NextField
        If Mid$(sLine, i2 - 1, 1) <> """" Then GoTo NextField

        Select Case (i2 - i1 - 2)
            Case 15
                s = Mid$(sLine, i1 + 1, 15)
                If s Like "###############" Then
                    GetID = s
                    Exit Function
                End If
            Case 18
                s = Mid$(sLine, i1 + 1, 18)
                If s Like "#################[0-9X]" Then
                    GetID = s
                    Exit Function
                End If

        End Select

NextField:
        i1 = i2 + 1
    Wend
End Function
他的代码也已测试,同样的文件跟15楼Chen8013的方式运行时间不相上下
Tiger_Zhao 2014-07-04
  • 打赏
  • 举报
回复
引用 11 楼 of123 的回复:
你用 Input 方式打开一个几 G 的文件试试就知道了。用 Binary 瞬间完成。
你确定你的计时程序是正常的? 你确定你感觉的瞬间没有在秒这个数量级? SATA2硬盘的理论传输速度是3Gbps(300MB/sec),SATA3硬盘的理论传输速度是6Gbps(600MB/sec)。
CuiCanBin 2014-07-04
  • 打赏
  • 举报
回复
首先说注意: 1. 如果在意性能问题,请勿用正则表达式。正则表达式可能比用自己的代码分析慢几十倍。只不过平时我们处理的量小,感觉不出来。 2. 最好不要用 ODBC 等过渡方式,因为你不能保证每台机都有相应 ODBC 的驱动。再说了,自己分析读取代码并不复杂,很简单。 方法: 1. 14M 的大小在以前来说是很大,但针对现在的硬件来说很容易了。因此建议一次性读入 String 中,为了防止区域、中英文等问题,最好以二进制方式读取如下: Open strYourFileName For Binary As #intFreeFileNum 然后用 InputB 语句读入到字符串 2. 可以用 Instr 来逐个定位位置来解析出身份证;若想简单但,用 Split 拆分,先拆分回车换行,这样就得到了每一行的内容,然后对每一行再以逗号拆分,这样就得到每个具体元素了(姓名、日期、身份证等等) 备注: 1. 如果是用 VB.NET,有逐行读取的方法,这样可以避免首次加载的长时间问题。 2. 如果还是觉得性能不够,可以用 C 写一个 DLL 来读取分析文件,然后开放给 VB,作为 COM 来调用。
yachong 2014-07-04
  • 打赏
  • 举报
回复
看楼主贴的这几行,从左向右数身份证号位置不确定,从右向左数是固定的。
of123 2014-07-04
  • 打赏
  • 举报
回复
你用 Input 方式打开一个几 G 的文件试试就知道了。用 Binary 瞬间完成。
Tiger_Zhao 2014-07-04
  • 打赏
  • 举报
回复
正则对象适合多重复杂的匹配,使得代码能保持简洁。
但是易用性通常和效率成反比的。
身份证号这种匹配实在太简单了,没有用正则对象的必要。

又:VB 的 Like 运算因为支持的表达式很简单,速度和一般的字符串操着比并不慢。
舉杯邀明月 2014-07-04
  • 打赏
  • 举报
回复
看来用正则,速度上是比较慢的啊。
舉杯邀明月 2014-07-04
  • 打赏
  • 举报
回复
Option Explicit

Private Sub Command1_Click()
   Const SEPSTR   As String = ""","""
      Dim strRlt() As String
      Dim strTemp As String
      Dim dTime   As Double
      Dim lNum    As Long
      Dim iFn     As Integer
      Dim i&, p&, ps&, pe&

   iFn = FreeFile()
   dTime = Timer()
   Open "E:\Tools\2.txt" For Input As #iFn
   Line Input #iFn, strTemp
   lNum = LOF(iFn) / Seek(iFn)
   ReDim strRlt(lNum)
   p = -1&: Seek iFn, 1
   Do
      If (EOF(iFn)) Then Exit Do
      p = p + 1&
      If (p > lNum) Then
         lNum = lNum + 160
         ReDim Preserve strRlt(lNum)
      End If
      Line Input #iFn, strTemp
      i = InStr(20, strTemp, "/")
      ps = InStr(i + 12, strTemp, SEPSTR) + 3
      pe = InStr(ps, strTemp, SEPSTR)
      strRlt(p) = Mid$(strTemp, ps, pe - ps)
   Loop
   Close
   Me.Print "耗时:" & Format$(Timer() - dTime, "0.00秒")
   Me.Print "提取数据:" & p + 1
   ' 结果检查:
   pe = -1&
   For i = 0 To p
      ps = Len(strRlt(i))
      If (ps <> 15& And ps <> 18&) Then
         Me.Print i + 1; "出错"
         pe = 0
      End If
   Next
   If (pe) Then Me.Print "数据检验合格。"
End Sub
楼主提供给我的样本文件 3.83MB,共15456条数据, 我复制5倍, 共19.1MB、77280条数据。 在我的一台配置比较差的办公电脑上,全部处理完仅1秒钟。 单读取文件,约0.9秒。
Tiger_Zhao 2014-07-03
  • 打赏
  • 举报
回复
1)读文件不无需优化
(这个比较符合我的预期,系统和硬盘都有缓存,就算一个个字符读也不应该慢的,5楼那种“快很多”的情况前提不明确。)
2)输出优化
自己做个类似 StringBuilder 的拼字符串功能,文本框只需赋值一次。
3)解析优化
a.正则需要看具体代码了
b.个人感觉这种特定规则的自己查找应该比正则快
Function GetID(sLine As String) As String
Dim lLength As Long
Dim i1 As Long '字段开始位置
Dim i2 As Long '字段结束的逗号位置
Dim s As String

lLength = Len(sLine)
If lLength = 0 Then Exit Function

i1 = 1
While i1 <= lLength
i2 = InStr(i1, sLine, ",")
If i2 = 0 Then i2 = lLength + 1

If (i2 - i1) <= 2 Then GoTo NextField
If Mid$(sLine, i1, 1) <> """" Then GoTo NextField
If Mid$(sLine, i2 - 1, 1) <> """" Then GoTo NextField

Select Case (i2 - i1 - 2)
Case 15
s = Mid$(sLine, i1 + 1, 15)
If s Like "###############" Then
GetID = s
Exit Function
End If
Case 18
s = Mid$(sLine, i1 + 1, 18)
If s Like "#################[0-9X]" Then
GetID = s
Exit Function
End If

End Select

NextField:
i1 = i2 + 1
Wend
End Function
赵4老师 2014-07-03
  • 打赏
  • 举报
回复
为什么不直接InputB到一个String变量中,然后用正则表达式提取呢?
no000on 2014-07-03
  • 打赏
  • 举报
回复
引用 6 楼 Tiger_Zhao 的回复:
这样拍脑袋假象的分析,真不靠谱! A: 全程400秒 B: 只解析不输出,多少时间? C: 只读文件不解析,多少时间? 判断哪部分最花时间,在考虑如何优化。
我用NtReadFile ,OpenFile读取文件内容,用了17M文本文件测试 只读不输出基本都在15-30毫秒左右 输出到文本框在600-1500毫秒 处理数据这块消耗时间比较长
no000on 2014-07-03
  • 打赏
  • 举报
回复
引用 9 楼 Tiger_Zhao 的回复:
1)读文件不无需优化 (这个比较符合我的预期,系统和硬盘都有缓存,就算一个个字符读也不应该慢的,5楼那种“快很多”的情况前提不明确。) 2)输出优化 自己做个类似 StringBuilder 的拼字符串功能,文本框只需赋值一次。 3)解析优化 a.正则需要看具体代码了 b.个人感觉这种特定规则的自己查找应该比正则快
Function GetID(sLine As String) As String
    Dim lLength     As Long
    Dim i1          As Long    '字段开始位置
    Dim i2          As Long    '字段结束的逗号位置
    Dim s           As String

    lLength = Len(sLine)
    If lLength = 0 Then Exit Function

    i1 = 1
    While i1 <= lLength
        i2 = InStr(i1, sLine, ",")
        If i2 = 0 Then i2 = lLength + 1

        If (i2 - i1) <= 2 Then GoTo NextField
        If Mid$(sLine, i1, 1) <> """" Then GoTo NextField
        If Mid$(sLine, i2 - 1, 1) <> """" Then GoTo NextField

        Select Case (i2 - i1 - 2)
            Case 15
                s = Mid$(sLine, i1 + 1, 15)
                If s Like "###############" Then
                    GetID = s
                    Exit Function
                End If
            Case 18
                s = Mid$(sLine, i1 + 1, 18)
                If s Like "#################[0-9X]" Then
                    GetID = s
                    Exit Function
                End If

        End Select

NextField:
        i1 = i2 + 1
    Wend
End Function
我试试你这个方法,回头告诉结论 我先说说我自己方法测试的结果 17M文件 13W多数据 NtReadFile ,OpenFile用这个两个函数读取文件内容 优化了一下正则表达式 将数据加载到listview用时5秒左右 6M文件 20W多数据 同样的操作用了10秒多 处理文件看来跟文件的大小没有关系
Tiger_Zhao 2014-07-02
  • 打赏
  • 举报
回复
这样拍脑袋假象的分析,真不靠谱!

A: 全程400秒
B: 只解析不输出,多少时间?
C: 只读文件不解析,多少时间?
判断哪部分最花时间,在考虑如何优化。
of123 2014-07-02
  • 打赏
  • 举报
回复
用 Input 方式打开,大文件载入就需要较长时间。 我以前做过大文件数据提取和格式转换的工作,是采用 Binary 方式打开,每次取入 4096 或更多字节数据。用 Byte 数组读入,用 StrConv 函数转成字符串。 你也可以试试。 这样做的好处是,你可以采用 Globe 方式用正则表达式在一个大块中找到多个身份证号码。需要解决的问题是,你每次截取的数据很可能不是整行的结尾。因此,你需要从反向找到换行符,截掉后面的尾巴,连接到下一块的前头。 我以前的任务,采用这样的方式,处理几个 G 的数据,比 Input 方式快很多。
no000on 2014-07-02
  • 打赏
  • 举报
回复
引用 2 楼 sysdzw 的回复:
ODBC Standard: "Driver={Microsoft Text Driver (*.txt; *.csv)};Dbq=c:\txtFilesFolder\;Extensions=asc,csv,tab,txt;" OLE DB Standard: "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\txtFilesFolder\;Extended Properties=""text;HDR=Yes;FMT=Delimited"""
数据库引擎已经试过了,不行的
舉杯邀明月 2014-07-02
  • 打赏
  • 举报
回复
楼主,你用附件的形式,
发个样本文件到我邮箱里,
我试一下有没有别的方法。
你这样贴出来的,我在手机上看着不方便。
加载更多回复(2)

7,785

社区成员

发帖
与我相关
我的任务
社区描述
VB 基础类
社区管理员
  • VB基础类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧