You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

VB.NET在.NET Framework 4.8下无需读取全文件获取文件末尾行的方案

反向读取文件末尾指定行数实现方案(.NET Framework 4.8 兼容)

核心原理

直接通过FileStream将文件指针定位到文件尾部,从后往前扫描换行符,累计匹配到指定数量的换行符后,再读取对应区间的内容转成文本即可,全程不需要加载整个文件到内存,读取速度不受文件整体大小影响。

注意事项

  • 兼容Windows风格\r\n和Unix风格\n两种换行格式,避免出现行截断
  • 支持自定义文本编码,可根据实际日志文件的编码调整参数
  • 自动处理边界情况:如果文件实际行数小于需要读取的行数,直接返回全部文件内容

VB 实现代码

Imports System.IO
Imports System.Text

' 方法参数:文件路径、要读取的末尾行数、文本编码(默认UTF-8,可按需调整)
Public Function ReadLastLines(filePath As String, linesCount As Integer, Optional encoding As Encoding = Nothing) As String
    If encoding Is Nothing Then encoding = Encoding.UTF8
    If linesCount <= 0 Then Return String.Empty
    If Not File.Exists(filePath) Then Return String.Empty
    
    Const bufferSize As Integer = 4096 ' 单次读取缓冲区大小,可按需调整
    Dim lineTerminator As Char = ControlChars.Lf ' 以换行符作为行判定基准
    Dim foundLines As Integer = 0
    Dim resultBuilder As New StringBuilder()
    
    Using fs As New FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
        ' 处理空文件情况
        If fs.Length = 0 Then Return String.Empty
        
        Dim filePosition As Long = fs.Length - 1
        Dim buffer As Byte() = New Byte(bufferSize - 1) {}
        Dim isFirstBlock As Boolean = True
        
        While filePosition >= 0 AndAlso foundLines < linesCount
            Dim readSize As Integer = CInt(Math.Min(bufferSize, filePosition + 1))
            filePosition -= readSize
            fs.Seek(filePosition, SeekOrigin.Begin)
            fs.Read(buffer, 0, readSize)
            
            ' 从后往前扫描当前缓冲区的换行符
            For i As Integer = readSize - 1 To 0 Step -1
                If buffer(i) = AscW(lineTerminator) Then
                    foundLines += 1
                    If foundLines = linesCount Then
                        ' 已经找够行数,截取当前位置之后的内容
                        Dim segmentLength As Integer = readSize - i - 1
                        If segmentLength > 0 Then
                            resultBuilder.Insert(0, encoding.GetString(buffer, i + 1, segmentLength))
                        End If
                        Exit For
                    End If
                End If
            Next
            
            ' 还没找够行数,把整个缓冲区内容拼到结果前面
            If foundLines < linesCount Then
                resultBuilder.Insert(0, encoding.GetString(buffer, 0, readSize))
            End If
            
            ' 处理最后一行末尾没有换行符的情况
            If isFirstBlock Then
                isFirstBlock = False
                If buffer(readSize - 1) <> AscW(lineTerminator) Then
                    foundLines += 1
                End If
            End If
        End While
    End Using
    
    Return resultBuilder.ToString().TrimEnd(ControlChars.Cr, ControlChars.Lf)
End Function

' 调用示例
Sub Main()
    Dim filePath = "C:\file.xy"
    Dim linesCount = 5
    ' 若日志是系统默认编码用Encoding.Default,UTF-8的话可以不传第三个参数
    Dim result = ReadLastLines(filePath, linesCount, Encoding.Default)
    Console.WriteLine(result)
End Sub

性能对比

你原有实现中File.ReadAllLines会把整个文件的内容全部加载到内存拆分出行数组,当日志文件达到GB级别时,会占用大量内存且读取耗时极长。
本实现仅会读取末尾需要的行数附近的少量内容,即使是10GB以上的日志文件,读取最后5行的耗时也能稳定在毫秒级。


内容的提问来源于stack exchange,提问作者TheDomis4

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 05:57:01