设置FileStream.Seek的位置/索引以检索数据VB.NET的“块”

时间:2012-10-09 16:33:05

标签: vb.net file-io out-of-memory

我目前正在研究一种接收文本文件的方法,并将文件减少到~10 MB。此方法用于截断日志文件并将其保持在10 MB范围内。

代码背后的逻辑基本上就是这样......如果文件是250 MB或更大,那么读取字节直到数组达到250 MB。将其存储到StringBuilder,设置下一次读取的位置并重复,直到StringBuilder包含~10 MB的数据。然后写出删除所有数据的文件,只留下10 MB的最新写入。

为防止将切割线减半,它会检查最后CrLf的位置,然后从该点向前写出所有数据。

我的问题是我无法在首次阅读后获得正确定位的搜索。它首先正确读取数据,然后当我使用上一次读取的位置进行下一次迭代时,它“忽略”该位置并再次从文件的开头读取。

If logFile.Length > (1024 * 1024 * 250) Then
    Dim DataToDelete As Integer = logFile.Length - (1024 * 1024 * 250)
    Dim ArrayIndex As Integer = 0
    While DataToDelete > 0
        Using fs As FileStream = New FileStream(logFile.FullName, FileMode.Open, FileAccess.ReadWrite)
            fs.Seek(ArrayIndex, SeekOrigin.Begin)
            If strBuilder.Length < (1024 * 1024 * 250) Then
                Dim bytes() As Byte = New Byte((1024 * 1024 * 250)) {}
                Dim n As Integer = fs.Read(bytes, 0, (1024 * 1024 * 250))
                ArrayIndex = bytes.Length
                Dim enc As Encoding = Encoding.UTF8
                strBuilder.Append(enc.GetString(bytes))
            Else
                If DataToDelete - strBuilder.Length < 0 And strBuilder.Length > (1024 * 1024 * My.Settings.Threshold) Then
                    Dim DataToCut As Integer = strBuilder.Length - (1024 * 1024 * My.Settings.Threshold)
                    While Not (strBuilder.Chars(DataToCut).ToString.Equals(vbCr)) And DataToCut <> 0
                        DataToCut -= 1
                    End While
                    strBuilder.Remove(0, DataToCut)
                    File.WriteAllText(logFile.FullName, strBuilder.ToString)
                Else
                    DataToDelete -= strBuilder.Length
                    strBuilder.Clear()
                End If
            End If
        End Using
    End While
End If

2 个答案:

答案 0 :(得分:1)

对于你正在做的事情,将整个文件加载到内存中是不必要的,也不是一个好主意。只读取你想要保留的日志文件部分(最后10MB)会好得多。例如,做这样的事情会更简单,更有效:

Private Sub ShrinkLog(ByVal filePath As String, ByVal maxSize As Integer)
    Dim buffer As String
    If New FileInfo(filePath).Length > maxSize Then
        Using reader As New StreamReader(filePath)
            reader.BaseStream.Seek(-maxSize, SeekOrigin.End)
            buffer = reader.ReadToEnd()
        End Using
        File.WriteAllText(filePath, buffer)
    End If
End Sub

还有其他方法可以做到这一点。如果您要保留文件的更大部分,甚至不将所有内容加载到内存中,而只是直接从一个流转到另一个流,那将更加高效。此外,这个简单的例子没有说明如何避免在文件的某个部分切断一行,但我确信你可以继续一次寻找一个字节,直到找到第一个换行符。

答案 1 :(得分:0)

这是我的最终结果,就像一个魅力!

        Dim Maxsize As Integer = (1024 * 1024 * My.Settings.Threshold)
    For Each logfile In filesToTrim
        Dim sb As New StringBuilder
        Dim buffer As String = String.Empty
        If logfile.Length > Maxsize Then
            Using reader As New StreamReader(logfile.FullName)
                reader.BaseStream.Seek(-Maxsize, SeekOrigin.End)
                buffer = reader.ReadToEnd()
                sb.Append(buffer)
            End Using
            Dim Midpoint As Integer = 0
            While Not (sb.Chars(Midpoint).ToString.Equals(vbCr)) And Midpoint <> sb.Length - 1
                Midpoint += 1
            End While
            sb.Remove(0, Midpoint)
            File.WriteAllText(logfile.FullName, sb.ToString)
        End If
    Next