我目前正在研究一种接收文本文件的方法,并将文件减少到~10 MB.此方法用于截断日志文件并使其保持在10 MB的限制范围内. 代码背后的逻辑基本上就是这样……如果文件是250 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对于你正在做的事情,将整个文件加载到内存中是不必要的,也不是一个好主意.只读取你想要保留的日志文件部分(最后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
还有其他方法可以做到这一点.如果您要保留文件的更大部分,甚至不将所有内容加载到内存中,而只是直接从一个流转到另一个流,那将更加高效.此外,这个简单的例子没有说明如何避免在文件的某个部分切断一行,但我确信你可以继续寻找一个字节,直到你找到第一个换行符.