4

私は現在、テキスト ファイルを取り込み、ファイルを 10 MB まで削減する方法に取り組んでいます。この方法は、ログ ファイルを切り捨て、10 MB の制限内に保つために使用されます。

コードの背後にあるロジックは基本的にこれです...ファイルが250 MB以上の場合、配列が250 MBに達するまでバイトを読み取ります。これをに保存し、次の読み取りのために位置を設定し、 〜10 MB のデータが含まStringBuilderれるまで繰り返します。StringBuilder次に、ファイルに書き込み、すべてのデータを消去し、最新の書き込みの 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
4

2 に答える 2

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 バイトずつ検索し続けることができると確信しています。

于 2012-10-09T18:15:38.583 に答える
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
于 2012-10-09T18:55:28.483 に答える