【问题标题】:Will Putting This Onto A background Worker Stop This Issue将其放在后台工作人员上会停止此问题
【发布时间】:2020-08-16 14:27:53
【问题描述】:

我已经尝试解决这个问题好几天了,但没有任何成功。我知道我已经创建了另一个与此问题相关的帖子,但不确定我是否应该继续另一个帖子而不是创建一个新帖子,因为我对 SO 的工作方式仍然很陌生,所以如果我以错误的方式处理这个问题,我深表歉意.

目标
从磁盘读取文本文件,将内容输出到文本框,然后我可以从中提取最后 3 行。这是我能想到的唯一方法。

文本文件不断被另一个正在运行的程序更新,但我仍然可以读取它,即使它正在使用但无法写入它。

我正在通过每 1 秒计时一次的计时器探测此文件,以获取最新信息。

现在问题...
我注意到一段时间后我的应用程序变得迟缓,当我尝试在屏幕上移动它或调整它的大小时很明显,CPU 使用率开始攀升至超过 33%

我的思考过程
由于读取文件是连续的,我想我可以将它移到 BackgroundWorker 上,据我了解,它会将它放在不同的线程上并减轻主 GUI 的一些负载。

我在这棵树上叫错了吗?

在开始学习如何使用 BackgroundWorker 的所有教科书之前,我正在接触更高级的用户。

这是我用来读取 txt 文件并将其输出到文本框的代码。我没有包含用于提取最后 3 行的代码,因为我认为这不是导致问题的部分。

我认为问题在于我每秒钟都在用计时器不断探测源文件,但不是 100% 肯定是诚实的。

 Dim strLogFilePath As String
    strLogFilePath = "C:\DSD\data.txt"

    Dim LogFileStream As FileStream
    Dim LogFileReader As StreamReader

    'Open file for reading
    LogFileStream = New FileStream(strLogFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)

    LogFileReader = New StreamReader(LogFileStream)

    'populate text box with the contents of the txt file
    Dim strRowText As String
    strRowText = LogFileReader.ReadToEnd()

    TextBox1.text = strRowText

    'Clean Up
    LogFileReader.Close()
    LogFileStream.Close()

    LogFileReader.Dispose()
    LogFileStream.Dispose()

【问题讨论】:

  • 如果您不需要在屏幕上查看文件的全部内容,请不要将其放在文本框中。这个操作,特别是在文件很大的情况下,它本身可能会导致性能问题。
  • 我认为这可能是我的问题的根源,不,我不需要查看全部内容,我只对任何给定时间的最后 3 行感兴趣。如果不在文本框中,您将如何存储数据
  • 实际上你的存储在变量 strRowText 中,但你也可以使用 ReadAllLines 或 ReadLines 并保持最后三行加载
  • 我很感激您可能想自己解决这个问题,但只是想让您知道这个轮子已经存在 - 一个名为 mTAIL 的应用程序
  • 这是一个正常的意外,TextBox 很快就会变得非常低效。避免该问题的一个简单方法是不关闭文件,您只会得到添加的文本。

标签: vb.net backgroundworker


【解决方案1】:

首先,您应该使用Using 关键字而不是手动释放对象,因为这样可以保证即使发生意外异常也会释放对象,例如:

' You can initialize variables in one line
Dim strLogFilePath As String = "C:\DSD\data.txt"

Using LogFileStream As New FileStream(strLogFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
    ' Everything goes in here
End Using

我的解决方案不需要阅读器。读取将手动完成。

接下来,您需要读取流的最后 n 行(在您的情况下为 3)。当您只对最后几行感兴趣时读取整个文件是低效的。相反,您可以从头开始阅读,直到达到三个(或任意数量)行分隔符(基于 this answer):

Function ReadLastLines(
    NumberOfLines As Integer, Encoding As System.Text.Encoding, FS As FileStream,
    Optional LineSeparator As String = vbCrLf
) As String
    Dim NewLineSize As Integer = Encoding.GetByteCount(LineSeparator)
    Dim NewLineCount As Integer = 0
    Dim EndPosition As Long = Convert.ToInt64(FS.Length / NewLineSize)
    Dim NewLineBytes As Byte() = Encoding.GetBytes(LineSeparator)
    Dim Buffer As Byte() = Encoding.GetBytes(LineSeparator)

    For Position As Long = NewLineSize To EndPosition Step NewLineSize
        FS.Seek(-Position, SeekOrigin.End)
        FS.Read(Buffer, 0, Buffer.Length)

        If Encoding.GetString(Buffer) = LineSeparator Then
            NewLineCount += 1

            If NewLineCount = NumberOfLines Then
                Dim ReturnBuffer(CInt(FS.Length - FS.Position)) As Byte
                FS.Read(ReturnBuffer, 0, ReturnBuffer.Length)
                Return Encoding.GetString(ReturnBuffer)
            End If
        End If
    Next

    ' Handle case where number of lines in file is less than NumberOfLines
    FS.Seek(0, SeekOrigin.Begin)
    Buffer = New Byte(CInt(FS.Length)) {}
    FS.Read(Buffer, 0, Buffer.Length)
    Return Encoding.GetString(Buffer)
End Function

用法:

Using LogFileStream As New FileStream(strLogFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
    ' Depending on system, you may need to supply an argument for the LineSeparator param
    Dim LastThreeLines As String = ReadLastLines(3, System.Text.Encoding.UTF8, LogFileStream)
    ' Do something with the last three lines
    MsgBox(LastThreeLines)
End Using

请注意,我没有测试过这段代码,我确信它可以改进。它也可能不适用于所有编码,但听起来它应该比您当前的解决方案更好,并且它适用于您的情况。

编辑:另外,为了回答您的问题,IO 操作通常应该异步执行以避免阻塞 UI。您可以使用任务或 BackgroundWorker 来执行此操作。它可能不会使它更快,但它会使您的应用程序更具响应性。最好在任务开始之前表明正在加载某些内容。

如果您知道文件何时被写入,您可以设置一个标志开始读取,然后在读取最后一行时取消设置。如果它没有改变,就没有理由一遍又一遍地阅读它。

【讨论】:

  • 我只是想感谢 Audopolis 展示和解释了改进我的代码的更好方法。倒读文件是我从未想过的。
  • 很高兴能帮上忙!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-07
  • 1970-01-01
  • 2021-12-23
相关资源
最近更新 更多