【问题标题】:Fastest Method to (read, remove, write) to a Text File(读取、删除、写入)文本文件的最快方法
【发布时间】:2020-10-26 18:18:13
【问题描述】:

我编写了一个简单的程序,它逐行读取文本文件,如果当前读取的行有字母 (a-z A-Z),它将将该行写入另一个 txt 文件。

如果当前读取的行没有字母,它不会将该行写入新的文本文件。

我创建这个的目的是为了让会员在我的网站上注册,其中一些会员只使用数字作为用户名。我会将它们过滤掉,只保存字母名称。 (请专注于这个项目,我知道我可以只使用 php 的东西)

这已经很好用了,但是逐行读取并写入另一个文本文件需要一段时间(1 分钟内写入速度 150kb - 这不是我的驱动器,我有一个快速的 ssd)。

所以我想知道是否有更快的方法。我可以先“readalllines”,但在大文件上它只会冻结我的程序,所以我不知道这是否也有效(我想专注于大 +1gb 文件)

这是我目前的代码:

 If System.IO.File.Exists(FILE_NAME) = True Then

            Dim objReader As New System.IO.StreamReader(FILE_NAME)

            Do While objReader.Peek() <> -1

                Dim myFile As New FileInfo(output)
                Dim sizeInBytes As Long = myFile.Length

                If sizeInBytes > splitvalue Then
                    outcount += 1
                    output = outputold + outcount.ToString + ".txt"
                    File.Create(output).Dispose()
                End If

                count += 1
                TextLine = objReader.ReadLine() & vbNewLine
                Console.WriteLine(TextLine)


                If CheckForAlphaCharacters(TextLine) Then
                    File.AppendAllText(output, TextLine)
                Else
                    found += 1
                    Label2.Text = "Removed: " + found.ToString
                    TextBox1.Text = TextLine
                End If

                Label1.Text = "Checked: " + count.ToString

            Loop

            MessageBox.Show("Finish!")

        End If

【问题讨论】:

  • 不是询问文件 I/O,而是要研究线程模型,在后台线程上执行所有文件 I/O。 (也许async/await 足够简单。)此外,您的程序“冻结”是因为您将业务逻辑与 UI 操作混合在一起(例如Label2.Text = )。通过在 UI 线程上运行这个长时间的操作,您会使 UI 无响应。如何实现这种分离有各种各样的模型(MVVM 就是其中之一)。
  • 好吧,只是为了测试目的,我还删除了所有的 ui 部分,只留下了文本编写部分。看起来速度从 1 分钟的 150kb 上升到 1 分钟的 200kb,这仍然很慢。逐行阅读并将其粘贴到另一个文本文件中似乎就是问题所在。不知道有没有更快的方法?
  • 好吧,文件 I/O 需要时间。这是同一主题的another question,那里的答案表明您不会获得比StreamReader.ReadLine() 更好的性能。我建议仔细查看的答案是关于使用单独的线程进行阅读和写作。 (想想生产者/消费者模型。)这样你的限速器(可能ReadLine())就不会被任何东西挡住。
  • 另一个考虑因素,CheckForAlphaCharacters(TextLine) 引入了多少延迟?该方法的实现方式有什么可以优化的吗?
  • splitvalue 的大小是多少?您可以将数据累积到 StringBuilder 中,然后一次性将其写入其中一个输出文件。

标签: vb.net


【解决方案1】:

首先,正如@Sean Skelly 所暗示的那样,反复更新 UI 控件是一项昂贵的操作。 但你更大的问题是 File.AppendAllText:

            If CheckForAlphaCharacters(TextLine) Then
                File.AppendAllText(output, TextLine)
            Else
                found += 1
                Label2.Text = "Removed: " + found.ToString
                TextBox1.Text = TextLine
            End If

追加所有文本(字符串,字符串)

打开一个文件,将指定的字符串附加到文件中,然后 关闭文件。如果文件不存在,此方法会创建一个 文件,将指定的字符串写入文件,然后关闭文件。 Source

您反复打开和关闭文件,导致开销。 AppendAllText 是一种方便的方法,因为它在一次调用中执行多个操作,但您现在可以看到为什么它在大循环中表现不佳。

修复很简单。开始循环时打开文件一次并在最后关闭它。确保即使发生异常也始终正确关闭文件。为此,您可以在 finally 块中调用 Close,或使用上下文管理器,即将文件写入操作保留在 Using 块中。

您也可以将打印内容删除到控制台。显示管理也有成本。或者您可以每 10K 行左右打印一次状态更新。

当您完成所有这些操作后,您应该会注意到性能有所提高。

【讨论】:

    【解决方案2】:

    我的最终代码 - 现在运行速度快了很多(1 分钟 500mbs)

     Using sw As StreamWriter = File.CreateText(output)
                For Each oneLine As String In File.ReadLines(FILE_NAME)
                    Try
                        If changeme = True Then
                            changeme = False
                            GoTo Again2
                        End If
    
                        If oneLine.Contains(":") Then
                            Dim TestString = oneLine.Substring(0, oneLine.IndexOf(":")).Trim()
                            Dim TestString2 = oneLine.Substring(oneLine.IndexOf(":")).Trim()
                            If CheckForAlphaCharacters(TestString) = False And CheckForAlphaCharacters(TestString2) = False Then
                                sw.WriteLine(oneLine)
                            Else
                                found += 1
                            End If
    
                        ElseIf oneLine.Contains(";") Or oneLine.Contains("|") Or oneLine.Contains(" ") Then
                            Dim oneLineReplac As String = oneLine.Replace(" ", ":")
                            Dim oneLineReplace As String = oneLineReplac.Replace("|", ":")
                            Dim oneLineReplaced As String = oneLineReplace.Replace(";", ":")
                            If oneLineReplaced.Contains(":") Then
                                Dim TestString3 = oneLineReplaced.Substring(0, oneLineReplaced.IndexOf(":")).Trim()
                                Dim TestString4 = oneLineReplaced.Substring(oneLineReplaced.IndexOf(":")).Trim()
                                If CheckForAlphaCharacters(TestString3) = False And CheckForAlphaCharacters(TestString4) = False Then
                                    sw.WriteLine(oneLineReplaced)
                                Else
                                    found += 1
                                End If
                            Else
                                errors += 1
                                textstring = oneLine
                            End If
                        Else
                            errors += 1
                            textstring = oneLine
                        End If
                        count += 1
                    Catch
                        errors += 1
                        textstring = oneLine
                    End Try
                Next
    
    
            End Using
    

    【讨论】:

      猜你喜欢
      • 2012-08-26
      • 1970-01-01
      • 1970-01-01
      • 2013-05-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多