none
怎样避免文件锁定? RRS feed

  • 问题

  • Imports System.IO
    
    
    Public Class MyLogWriter
        Public Sub WriteLog(ByVal sLog As String)
            Dim MyLogFileName As String
            Try
    
                Dim CurrentDir As String = System.Threading.Thread.GetDomain.BaseDirectory & "Log"
    
                If Not My.Computer.FileSystem.DirectoryExists(CurrentDir) Then
                    My.Computer.FileSystem.CreateDirectory(CurrentDir)
                End If
    
                MyLogFileName = Format(Now(), "yyyyMMdd") & ".log"
                Dim MyLogFile As New FileStream(CurrentDir & "\" & MyLogFileName, FileMode.Append)
                Dim MyLogWriter As New StreamWriter(MyLogFile)
                MyLogWriter.WriteLine(Now.ToString & "  " & sLog)
                MyLogWriter.Close()
                MyLogFile.Close()
            Catch ex As Exception
                WriteLog(ex.Message)
            End Try
        End Sub
    End Class
    写了这样一个类,用来给我的服务记录log,但是当log比较频繁的时候,经常会锁定文件,导致无法写入,报错信息为:20091103.log正由另一进程使用,因此该进程无法访问该文件。导致服务占用的内存越来越大.
        有没有好办法来避免这种情况?或者换个记录log的方式?请大家提供点思路,谢谢~!
    2009年11月3日 3:23

答案

  • 谢谢各位的提示:现在已经根据大家的建议修改如下:
    Imports System.IO
    
    
    Public Class MyLogWriter
        Private MsgLock As New Object
    
        Public Sub WriteLog(ByVal sLog As String)
            Dim MyLogFileName As String
            Dim MyLogFile As FileStream
            Dim MyLogWriter As StreamWriter
    
            Try
                Dim CurrentDir As String = System.Threading.Thread.GetDomain.BaseDirectory & "Log"
    
                If Not My.Computer.FileSystem.DirectoryExists(CurrentDir) Then
                    My.Computer.FileSystem.CreateDirectory(CurrentDir)
                End If
    
                MyLogFileName = Format(Now(), "yyyyMMdd") & ".log"
    
                SyncLock MsgLock
                    MyLogFile = New FileStream(CurrentDir & "\" & MyLogFileName, FileMode.Append)
                    MyLogWriter = New StreamWriter(MyLogFile)
                    MyLogWriter.WriteLine(Now.ToString & "  " & sLog)
                    MyLogWriter.Close()
                    MyLogFile.Close()
                End SyncLock
    
            Catch ex As Exception
                WriteLog(ex.Message)
            Finally
    
            End Try
        End Sub
    End Class
       不知道这么写对不对?
       继续观察中~~

    2009年11月3日 10:16

全部回复

  • 加一个lock锁


    Wenn ich dich hab’,gibt es nichts, was unerträglich ist.坚持不懈!My blog~~~
    2009年11月3日 4:25
    版主
  • 你好!
         我认为问题出在Try...Catch的捕获方式上,你看如下代码:
            Try
    
                Dim CurrentDir As String = System.Threading.Thread.GetDomain.BaseDirectory & "Log"
    
                If Not My.Computer.FileSystem.DirectoryExists(CurrentDir) Then
                    My.Computer.FileSystem.CreateDirectory(CurrentDir)
                End If
    
                MyLogFileName = Format(Now(), "yyyyMMdd") & ".log"
                Dim MyLogFile As New FileStream(CurrentDir & "\" & MyLogFileName, FileMode.Append)
                Dim MyLogWriter As New StreamWriter(MyLogFile)
                MyLogWriter.WriteLine(Now.ToString & "  " & sLog)
                MyLogWriter.Close()
                MyLogFile.Close()
            Catch ex As Exception
                WriteLog(ex.Message)
            End Try
    
    在你执行Close一些流之前可能会抛出异常,这会导致Close并没有执行,然后就执行Catch中的WriteLog方法了,这时又需要使用这个文件了,但是上次的流还没有关闭,所以出现了这个问题!
    尝试把Close语句写在Finally语句块中!
    周雪峰
    • 已建议为答案 sysdzw 2009年11月3日 6:26
    2009年11月3日 4:33
    版主
  • 你好!
         我认为问题出在Try...Catch的捕获方式上,你看如下代码:
            Try
    
    
    
                Dim CurrentDir As String = System.Threading.Thread.GetDomain.BaseDirectory & "Log"
    
    
    
                If Not My.Computer.FileSystem.DirectoryExists(CurrentDir) Then
    
                    My.Computer.FileSystem.CreateDirectory(CurrentDir)
    
                End If
    
    
    
                MyLogFileName = Format(Now(), "yyyyMMdd") & ".log"
    
                Dim MyLogFile As New FileStream(CurrentDir & "\" & MyLogFileName, FileMode.Append)
    
                Dim MyLogWriter As New StreamWriter(MyLogFile)
    
                MyLogWriter.WriteLine(Now.ToString & "  " & sLog)
    
                MyLogWriter.Close()
    
                MyLogFile.Close()
    
            Catch ex As Exception
    
                WriteLog(ex.Message)
    
            End Try
    
    
    
    
    在你执行Close一些流之前可能会抛出异常,这会导致Close并没有执行,然后就执行Catch中的WriteLog方法了,这时又需要使用这个文件了,但是上次的流还没有关闭,所以出现了这个问题!
    尝试把Close语句写在Finally语句块中!
    周雪峰

    好的,我试试.
    • 已建议为答案 sysdzw 2009年11月3日 6:26
    2009年11月3日 4:55
  • 加一个lock锁


    Wenn ich dich hab’,gibt es nichts, was unerträglich ist.坚持不懈!My blog~~~

    能说的更详细些吗?lock锁没用过.
    2009年11月3日 4:55
  • Imports System.IO
    
    
    Public Class MyLogWriter
        Dim MyLogFileName As String
        Dim MyLogFile As FileStream
        Dim MyLogWriter As StreamWriter
    
        Public Sub WriteLog(ByVal sLog As String)
    
            Try
    
                Dim CurrentDir As String = System.Threading.Thread.GetDomain.BaseDirectory & "Log"
    
                If Not My.Computer.FileSystem.DirectoryExists(CurrentDir) Then
                    My.Computer.FileSystem.CreateDirectory(CurrentDir)
                End If
    
                MyLogFileName = Format(Now(), "yyyyMMdd") & ".log"
                MyLogFile = New FileStream(CurrentDir & "\" & MyLogFileName, FileMode.Append)
                MyLogWriter = New StreamWriter(MyLogFile)
                MyLogWriter.WriteLine(Now.ToString & "  " & sLog)
    
            Catch ex As Exception
                WriteLog(ex.Message)
            Finally
                MyLogWriter.Close()
                MyLogFile.Close()
            End Try
        End Sub
    End Class
        现在改成这样了,好像还是不行,还是同样的报错,我觉得应该是StreamWriter的速度比较快,而fileStream由于涉及到磁盘操作,所以相对速度比较慢才造成文件未关闭,而Streamwirter又要写入吧.由于我写的服务有的时候会有比较多的log,所以才有上述情况.
        请大家给点好的建议,谢谢.
       
    2009年11月3日 7:23
  • 你好!
         把这行去掉试试:
         WriteLog(ex.Message)
         我还是怀疑stream没有释放导致的这个问题!
         另外,检查一下是否有其他进程在使用这个文件!

    周雪峰
    2009年11月3日 9:16
    版主
  • 加一个lock锁


    Wenn ich dich hab’,gibt es nichts, was unerträglich ist.坚持不懈!My blog~~~

    能说的更详细些吗?lock锁没用过.
    Private messagesLock As New Object 

    Public Sub WriteLog(ByVal sLog As String)
               SyncLock messagesLock 
    '''your code

     End SyncLock 
     End Sub

    http://feiyun0112.cnblogs.com/
    2009年11月3日 9:25
    版主
  • 你好!
         把这行去掉试试:
         WriteLog(ex.Message)
         我还是怀疑stream没有释放导致的这个问题!
         另外,检查一下是否有其他进程在使用这个文件!

    周雪峰

    把WriteLog(ex.Message)去掉也有报错的,最早就是因为没有使用try catch结构,所以导致服务崩溃.
    另外,有可能存在别的进程使用这个文件的状况,因为服务是多线程,并且有2个timer会定时做一些操作,有可能多个线程同时写log.


       我刚才在考虑做成以下的方式,设置一个公共string变量比如sAllLog,每次调用writerlog方法的时候其实仅把log内容追加到sAllLog中,然后再用一个timer,定时,或者当sAlllog.length超过某个长度的时候一次性写入log文件.同时把sAllLog的内容清空.
       但是这样担心一个问题,就是timer在执行的时候,如果正好又有log要写,这个时候清空sAllLog和往里添加log内容如果控制的不好,是不是会造成log丢失呢?
      
    2009年11月3日 9:26
  • 如果是多线程,你尝试加锁!
    周雪峰
    2009年11月3日 9:47
    版主
  • 谢谢各位的提示:现在已经根据大家的建议修改如下:
    Imports System.IO
    
    
    Public Class MyLogWriter
        Private MsgLock As New Object
    
        Public Sub WriteLog(ByVal sLog As String)
            Dim MyLogFileName As String
            Dim MyLogFile As FileStream
            Dim MyLogWriter As StreamWriter
    
            Try
                Dim CurrentDir As String = System.Threading.Thread.GetDomain.BaseDirectory & "Log"
    
                If Not My.Computer.FileSystem.DirectoryExists(CurrentDir) Then
                    My.Computer.FileSystem.CreateDirectory(CurrentDir)
                End If
    
                MyLogFileName = Format(Now(), "yyyyMMdd") & ".log"
    
                SyncLock MsgLock
                    MyLogFile = New FileStream(CurrentDir & "\" & MyLogFileName, FileMode.Append)
                    MyLogWriter = New StreamWriter(MyLogFile)
                    MyLogWriter.WriteLine(Now.ToString & "  " & sLog)
                    MyLogWriter.Close()
                    MyLogFile.Close()
                End SyncLock
    
            Catch ex As Exception
                WriteLog(ex.Message)
            Finally
    
            End Try
        End Sub
    End Class
       不知道这么写对不对?
       继续观察中~~

    2009年11月3日 10:16