【问题标题】:Reading and parsing large delimited text files in VB.net在 VB.net 中读取和解析大型分隔文本文件
【发布时间】:2012-01-04 19:47:32
【问题描述】:

我正忙于一个应用程序,它读取大小从 5mb 到 1gb+ 的空间分隔日志文件,然后将此信息存储到 MySQL 数据库中,以供以后根据文件中包含的信息打印报告时使用。我尝试过/发现的方法有效,但速度很慢。

我做错了吗?还是有更好的方法来处理非常大的文本文件?

我尝试过如下使用 textfieldparser:

Using parser As New TextFieldParser("C:\logfiles\testfile.txt")
    parser.TextFieldType = FieldType.Delimited
    parser.CommentTokens = New String() {"#"}
    parser.Delimiters = New String() {" "}
    parser.HasFieldsEnclosedInQuotes = False
    parser.TrimWhiteSpace = True
    While Not parser.EndOfData
        Dim input As String() = parser.ReadFields()
        If input.Length = 10 Then
            'add this to a datatable
        End If
    End While
End Using

这可行,但对于较大的文件来说非常慢。

然后我尝试根据以下函数使用与文本文件的 OleDB 连接以及我事先写入目录的 schema.ini 文件:

Function GetSquidData(ByVal logfile_path As String) As System.Data.DataTable
    Dim myData As New DataSet
    Dim strFilePath As String = ""
    If logfile_path.EndsWith("\") Then
        strFilePath = logfile_path
    Else
        strFilePath = logfile_path & "\"
    End If
    Dim mySelectQry As String = "SELECT * FROM testfile.txt WHERE Client_IP <> """""
    Dim myConnection As New System.Data.OleDb.OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & strFilePath & ";Extended Properties=""text;HDR=NO;""")
        Dim dsCmd As New System.Data.OleDb.OleDbDataAdapter(mySelectQry, myConnection)
        dsCmd.Fill(myData, "logdata")
        If Not myConnection.State = ConnectionState.Closed Then
            myConnection.Close()
        End If
    Return myData.Tables("logdata")
End Function

schema.ini 文件:

[testfile.txt]
Format=Delimited( )
ColNameHeader=False
Col1=Timestamp text
Col2=Elapsed text
Col3=Client_IP text
Col4=Action_Code text
Col5=Size double
Col6=Method text
Col7=URI text
Col8=Ident text
Col9=Hierarchy_From text
Col10=Content text

有人知道如何更快地读取这些文件吗?

-编辑- 更正了上面代码中的一个错字

【问题讨论】:

  • 您可能会考虑使用logparser,而不是尝试自己实现它。
  • 这些方法是否一次读取整个文件?如果您查看程序的内存,它是否会超过您正在读取的文件的大小(500MB-1GB)?如果是这样,您可能需要使用一种读取文件的方法,该方法可以一次读取一行文件。
  • @AakashM 谢谢肯定会调查的。

标签: mysql vb.net visual-studio-2010 data-import


【解决方案1】:

那里有两个可能很慢的操作:

  • 文件读取
  • 向数据库中插入大量数据

将它们分开并测试最耗时的。 IE。编写一个仅读取文件的测试程序,以及另一个仅插入大量记录的测试程序。看看哪个最慢。

一个问题可能是您正在将整个文件读入内存?

尝试使用 Stream 逐行读取它。这是code example copied from MSDN

Imports System
Imports System.IO

Class Test
    Public Shared Sub Main()
        Try
            ' Create an instance of StreamReader to read from a file.
            ' The using statement also closes the StreamReader.
            Using sr As New StreamReader("TestFile.txt")
                Dim line As String
                ' Read and display lines from the file until the end of
                ' the file is reached.
                Do
                    line = sr.ReadLine()
                    If Not (line Is Nothing) Then
                        Console.WriteLine(line)
                    End If
                Loop Until line Is Nothing
            End Using
        Catch e As Exception
            ' Let the user know what went wrong.
            Console.WriteLine("The file could not be read:")
            Console.WriteLine(e.Message)
        End Try
    End Sub
End Class

【讨论】:

  • 感谢 MarkJ 的回答,我无法打开您提供的链接 :( 认为我的 ISP 今天可能有一些问题...我已经尝试使用 streamreader.readline 功能但没有看到它有很大的不同(而且对于较大的文件,我得到一个 system.outofmemory 异常)。这是你的建议吗?
  • @DonnavandeGroot 我已将链接中的代码示例复制到我的答案中。我还编辑了我的答案,建议您进行一些实验以确定文件读取或数据库插入是否是瓶颈。这就是我首先要做的事情
  • 感谢您更新您的帖子 :) 我尝试使用流阅读器,但收到 system.outofmemory 异常 :( 而且我现在已经完全拆分了工作,它肯定是读取正在占用的文件超长
  • @DonnavandeGroot 内存不足异常?您是否将整个文件内容存储在内存中?我强烈建议不要这样做。我一次读入并处理一行
  • 我将每一行写入数据集,然后使用该数据集使用事务更新 MySQL innodb 数据库,以尝试减少执行数据库插入所花费的时间。我应该单独插入每一行吗?还是在读取文件时构建事务(因此不需要数据集)?
【解决方案2】:

从我的头上说,尝试引入某种线程来分散工作负载。

【讨论】:

  • 最有可能导致速度问题的是磁盘活动而不是 CPU 限制,因此线程很可能没有帮助。
  • 感谢您的想法,但我必须同意 CodyC 的上述观点。除非可能有办法将文件拆分为 x 行段,然后让不同的线程处理文件的每个段?这甚至可能/可行吗? [需要按行拆分,因为每行都是完整的记录,并且不能因行不完整而丢失数据]
猜你喜欢
  • 1970-01-01
  • 2017-01-22
  • 2015-10-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-15
  • 1970-01-01
  • 2019-12-07
相关资源
最近更新 更多