1

编辑:我试图更改代码,例如。而是使用不同的潜艇。但是现在,当某些事情发生变化时,程序只会崩溃。我已经禁用了日志记录、设置断点等,但程序并没有持续多久。这是 Visual Basic 日志中的错误消息(每次程序崩溃时都会出现):

System.Windows.Forms.dll 中出现“System.InvalidOperationException”类型的第一次机会异常

这是代码(如果您想知道 ExecProtectCompareModule 和 ExecProtect 是什么,我已经进行了一些进程监视器测试):

Imports System.IO
Imports System.Diagnostics
Imports System.Text
Imports System.Security.Cryptography
Public Class Form1
Dim processList As String
Dim processList2 As String
Public watchfolder As FileSystemWatcher
Dim log As String

Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click

    watchfolder = New System.IO.FileSystemWatcher()
    watchfolder.IncludeSubdirectories = True

    watchfolder.Path = TextBox1.Text



    watchfolder.NotifyFilter = IO.NotifyFilters.DirectoryName
    watchfolder.NotifyFilter = watchfolder.NotifyFilter Or _
                               IO.NotifyFilters.FileName
    watchfolder.NotifyFilter = watchfolder.NotifyFilter Or _
                               IO.NotifyFilters.Attributes


    AddHandler watchfolder.Changed, AddressOf logchange
    AddHandler watchfolder.Created, AddressOf logchange
    AddHandler watchfolder.Deleted, AddressOf logchange


    AddHandler watchfolder.Renamed, AddressOf logrename


    watchfolder.EnableRaisingEvents = True

    Button1.Enabled = False
    Button2.Enabled = True


End Sub
Private Sub logchange(ByVal source As Object, ByVal e As  _
                    System.IO.FileSystemEventArgs)
    '  Dim msg As String = Environment.NewLine & "File " & e.FullPath & " "

    ' Select Case e.ChangeType
    '  Case IO.WatcherChangeTypes.Created
    '  msg &= "has been created" + "  " + "Time:" + " " + Format(TimeOfDay)

    '  Case IO.WatcherChangeTypes.Deleted
    ' msg &= "has been deleted" + "  " + "Time:" + " " + Format(TimeOfDay)

    '   Case IO.WatcherChangeTypes.Changed
    ' msg &= "has been modified" + "  " + "Time:" + " " + Format(TimeOfDay)

    '  End Select






    'log &= msg
    'log &= Chr(13)






    'Dim writer As New IO.StreamWriter("log.txt", True)
    'writer.WriteLine(msg)
    'writer.Close()


    Label6.Text = e.FullPath
    md5checkdelay.Start()
End Sub

Public Sub logrename(ByVal source As Object, ByVal e As  _
                        System.IO.RenamedEventArgs)
    Select Case e.ChangeType
        Case IO.WatcherChangeTypes.Created
            Exit Sub
        Case IO.WatcherChangeTypes.Changed
            Exit Sub
        Case IO.WatcherChangeTypes.Deleted
            Exit Sub
        Case Else



            ' Dim msgrn As String = Environment.NewLine & "File " + e.OldName + " "
            ' msgrn &= "has been renamed to" + " " + e.Name + "  " + "Time:" + " " + Format(TimeOfDay)

            ' log &= msgrn
            ' log &= Chr(13)







            'Dim writer As New IO.StreamWriter("log.txt", True)
            'writer.WriteLine(msgrn)
            'writer.Close()

            Label5.Text = e.FullPath
            md5checkdelay.Start()
    End Select
End Sub
Sub md5check()

    Dim md5code As String

    Dim md5 As MD5CryptoServiceProvider = New MD5CryptoServiceProvider
    Dim f As FileStream = New FileStream(Label5.Text, FileMode.Open, FileAccess.Read, FileShare.Read, 8192)
    'f = New FileStream(e.FullPath, FileMode.Open, FileAccess.Read, FileShare.Read, 8192)
    md5.ComputeHash(f)
    'Dim ObjFSO As Object = CreateObject("Scripting.FileSystemObject")
    'Dim objFile = ObjFSO.GetFile(e.FullPath)

    Dim hash As Byte() = md5.Hash
    Dim buff As StringBuilder = New StringBuilder
    Dim hashByte As Byte
    For Each hashByte In hash
        buff.Append(String.Format("{0:X1}", hashByte))
    Next
    md5code = buff.ToString()

    If md5code = "D41D8CD98F0B24E980998ECF8427E" Then
        Dim frm2 As New Form2
        frm2.Show()
        f.Close()
    Else
        f.Close()
    End If
End Sub
Sub md5check2()

    Dim md5code As String

    Dim md5 As MD5CryptoServiceProvider = New MD5CryptoServiceProvider
    Dim f As FileStream = New FileStream(Label5.Text, FileMode.Open, FileAccess.Read, FileShare.Read, 8192)
    'f = New FileStream(e.FullPath, FileMode.Open, FileAccess.Read, FileShare.Read, 8192)
    md5.ComputeHash(f)
    'Dim ObjFSO As Object = CreateObject("Scripting.FileSystemObject")
    'Dim objFile = ObjFSO.GetFile(e.FullPath)

    Dim hash As Byte() = md5.Hash
    Dim buff As StringBuilder = New StringBuilder
    Dim hashByte As Byte
    For Each hashByte In hash
        buff.Append(String.Format("{0:X1}", hashByte))
    Next
    md5code = buff.ToString()

    If md5code = "D41D8CD98F0B24E980998ECF8427E" Then
        Dim frm2 As New Form2
        frm2.Show()
        f.Close()
    Else
        f.Close()
    End If
End Sub

Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click

    watchfolder.EnableRaisingEvents = False
    Button1.Enabled = True
    Button2.Enabled = False
End Sub

Private Sub Button3_Click(sender As System.Object, e As System.EventArgs) Handles Button3.Click
    Dim frm2 As New Form2
    frm2.ShowDialog()
End Sub

Private Sub ExecProtect_Tick(sender As System.Object, e As System.EventArgs) Handles ExecProtectMonitorModule.Tick
    For Each p As Process In Process.GetProcesses()
        processList = processList & " " & p.ProcessName & vbNewLine
    Next
    Label3.Text = processList
End Sub

Private Sub ExecProtectCompareModule_Tick(sender As System.Object, e As System.EventArgs) Handles ExecProtectCompareModule.Tick
    If Not Label2.Text = Label3.Text Then
        MsgBox("New process started!", 0 + 64)
        processList2refresh()
    End If
End Sub
Sub processList2refresh()
    For Each p As Process In Process.GetProcesses()
        processList2 = processList2 & " " & p.ProcessName & vbNewLine
        Exit Sub
    Next
End Sub

Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    For Each p As Process In Process.GetProcesses()
        processList2 = processList2 & " " & p.ProcessName & vbNewLine
    Next
    Label2.Text = processList2
End Sub

Private Sub md5checkdelay_Tick(sender As System.Object, e As System.EventArgs) Handles md5checkdelay.Tick
    'The timer that adds 1 second delay before it checks the md5code after the file(s) is changed
    Label4.Text = Label4.Text + 1
    If Label4.Text = 1 Then
        md5check()
    End If
End Sub

Private Sub md5checkdelay2_Tick(sender As System.Object, e As System.EventArgs) Handles md5checkdelay2.Tick
    'The timer that adds 1 second delay before it checks the md5code after the file(s) is changed but for the rename function instead
    Label7.Text = Label7.Text + 1
    If Label7.Text = 1 Then
        md5check2()
    End If
End Sub

结束类

编辑结束

我之前提出了一个问题,名为“仅监视文件中的 md5 代码的文件夹监视器崩溃”,有人告诉我关闭文件流并使用另一个代码来显示表单。但它不起作用。我制作了一个名为 TestForm 的表单,它不包含任何内容,只包含表单,因为当我尝试显示包含 PictureBoxes 等的 Form2 时整个程序关闭,并且我编写了代码以在 md5 时显示 TestForm修改后的文件的代码和我在代码中指定的md5代码相同,但是显示的表格只显示冻结,文件流不会关闭,我尝试使用 f.Close() 关闭文件流。但是,如果我编写代码以在修改文件的 md5 代码等于我在代码中指定的 md5 代码时显示一个 MsgBox,它就可以正常工作。这是代码:

Imports System.IO
Imports System.Diagnostics
Imports System.Text
Imports System.Security.Cryptography
Public Class Form1
Public watchfolder As FileSystemWatcher

Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click

    watchfolder = New System.IO.FileSystemWatcher()
    watchfolder.IncludeSubdirectories = True

    watchfolder.Path = TextBox1.Text



    watchfolder.NotifyFilter = IO.NotifyFilters.DirectoryName
    watchfolder.NotifyFilter = watchfolder.NotifyFilter Or _
                               IO.NotifyFilters.FileName
    watchfolder.NotifyFilter = watchfolder.NotifyFilter Or _
                               IO.NotifyFilters.Attributes


    AddHandler watchfolder.Changed, AddressOf logchange
    AddHandler watchfolder.Created, AddressOf logchange
    AddHandler watchfolder.Deleted, AddressOf logchange


    AddHandler watchfolder.Renamed, AddressOf logrename


    watchfolder.EnableRaisingEvents = True

    Button1.Enabled = False
    Button2.Enabled = True


End Sub
Private Sub logchange(ByVal source As Object, ByVal e As  _
                    System.IO.FileSystemEventArgs)
    If System.IO.Path.GetFileName(e.FullPath).ToLower = "log.txt" Then Exit Sub
    Dim msg As String = Environment.NewLine & "File " & e.FullPath & " "

    Select Case e.ChangeType
        Case IO.WatcherChangeTypes.Created
            msg &= "has been created" + "  " + "Time:" + " " + Format(TimeOfDay)

        Case IO.WatcherChangeTypes.Deleted
            msg &= "has been deleted" + "  " + "Time:" + " " + Format(TimeOfDay)

        Case IO.WatcherChangeTypes.Changed
            msg &= "has been modified" + "  " + "Time:" + " " + Format(TimeOfDay)

    End Select

    Dim writer As New IO.StreamWriter("log.txt", True)
    writer.WriteLine(msg)
    writer.Close()
    Dim md5code As String



    Dim md5 As MD5CryptoServiceProvider = New MD5CryptoServiceProvider
    Dim f As FileStream = New FileStream(e.FullPath, FileMode.Open, FileAccess.Read, FileShare.Read, 8192)
    f = New FileStream(e.FullPath, FileMode.Open, FileAccess.Read, FileShare.Read, 8192)
    md5.ComputeHash(f)
    Dim ObjFSO As Object = CreateObject("Scripting.FileSystemObject")
    Dim objFile = ObjFSO.GetFile(e.FullPath)

    Dim hash As Byte() = md5.Hash
    Dim buff As StringBuilder = New StringBuilder
    Dim hashByte As Byte
    For Each hashByte In hash
        buff.Append(String.Format("{0:X1}", hashByte))
    Next
    md5code = buff.ToString()
    If md5code = "D41D8CD98F0B24E980998ECF8427E" Then 'D41D8CD98F0B24E980998ECF8427E is the md5code of a blank txt file
        ' Dim frm2 As New Form2
        ' frm2.Show()
        TestForm.Show()
        f.Close()
    Else
        f.Close()
    End If
End Sub

Public Sub logrename(ByVal source As Object, ByVal e As  _
                        System.IO.RenamedEventArgs)
    Select Case e.ChangeType
        Case IO.WatcherChangeTypes.Created
            Exit Sub
        Case IO.WatcherChangeTypes.Changed
            Exit Sub
        Case IO.WatcherChangeTypes.Deleted
            Exit Sub
        Case Else
            Dim msgrn As String = Environment.NewLine & "File " + e.OldName + " "
            msgrn &= "has been renamed to" + " " + e.Name + "  " + "Time:" + " " + Format(TimeOfDay)
            Dim writer As New IO.StreamWriter("log.txt", True)
            writer.WriteLine(msgrn)
            writer.Close()
    End Select

End Sub

Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click

    watchfolder.EnableRaisingEvents = False
    Button1.Enabled = True
    Button2.Enabled = False
End Sub
End Class
4

1 回答 1

0
Dim f As FileStream = New FileStream(e.FullPath, FileMode.Open, _
         FileAccess.Read, FileShare.Read, 8192)
f = New FileStream(e.FullPath, FileMode.Open, FileAccess.Read, _
     FileShare.Read, 8192)
md5.ComputeHash(f)

编辑

注意到有什么奇怪的吗?您正在打开文件上的文件流,然后立即使用相同的变量在同一文件上打开另一个文件流,而不关闭第一个。这就是它报告在 VS 中打开的文件的原因之一。删除该行。f = New FileStream...

当事件因文件删除而触发时,您将在这里遇到另一个问题。

然后:

Dim ObjFSO As Object = CreateObject("Scripting.FileSystemObject")
Dim objFile = ObjFSO.GetFile(e.FullPath)

最后两个似乎没有做任何事情。对象已创建但未使用。但由于objFile是从相关文件构建的,它可能会阻止您删除或使用该文件。

Dim hash As Byte() = md5.Hash
Dim buff As StringBuilder = New StringBuilder
Dim hashByte As Byte
For Each hashByte In hash
    buff.Append(String.Format("{0:X1}", hashByte))
Next
md5code = buff.ToString()

由于您现在有了 MD5 代码,您应该关闭文件流 ( f) 以便您可以做其他事情。您不能在文件打开时删除或移动文件。

If md5code = "D41D8CD98F0B24E980998ECF8427E" Then 
    ' Dim frm2 As New Form2
    ' frm2.Show()
    TestForm.Show()
    f.Close()
Else
    f.Close()
End If

与您之前的代码一样,如果 TestForm 是表单类,则必须创建它的一个实例:

Dim frm As New TestForm
frm.Show                       ' or frm.ShowDialog

表单只是类。您必须在使用它们之前实例化它们。

继续编辑

最后,冻结是在日志事件中执行过多操作的结果(日志更改并计算 MD5 并显示新表单)。您可能已经注意到,在监视许多文件夹中的许多文件时,您的应用程序并没有变慢。那是因为文件观察器在不同的线程上运行。当您创建一个新表单的实例或从该事件中显示它时,该表单显然在该线程上运行。

您需要重新编写代码以删除与实际日志记录无关的内容。在那种情况下,您可以将更改的文件添加到表示待办事项列表的 List(of String) 中,而不是所有这些东西。执行 MD5 并在该列表的其他位置形成内容,以便在您的应用程序线程上进行。

最终编辑

如果您担心的只是表格冻结,请添加以下内容:

    watchfolder = New System.IO.FileSystemWatcher()
    watchfolder.SynchronizingObject = Me

只会耽误更重大的问题,但你似乎认为它很重要。接下来,我已经告诉过你 3 次了,但是如果文件操作是删除,你必须退出日志例程,因为你无法打开已删除的文件:

Case IO.WatcherChangeTypes.Deleted
    Exit Sub                         ' after the log

您将遇到的下一个问题是 2+ 文件已更改。您需要一种对文件/任务进行排队的方法。您为某些东西调用其他潜艇的方法确实将事情分解为离散的任务,但是那些称为 sub 的任务是从 FW 线程调用的,因此您只是将问题转移了。对于一个队列,我在想一个 List(of String),但是一个带有自己 BackgroundWorker 的新类(如您上一篇文章中所建议的)可能会更好。

Public Class FileMgr
  Friend thisFile As String
  Friend thisHash As String = ""

  Dim frm2 As Form2
  Private WithEvents bw As BackgroundWorker


  Public Sub New(ByVal f As String)
      thisFile = f

      bw = New BackgroundWorker
      AddHandler bw.DoWork, AddressOf ProcessFile
      ' Explorer might not be done creating it yet, 
      ' especially if you drop 3-4 files, so wait
      Threading.Thread.Sleep(250)
      ' start the BW with the name of the file
      bw.RunWorkerAsync(thisFile)
  End Sub

ProcessFile 只是您的(固定)MD5 子,带有新声明:

  Private Sub ProcessFile(ByVal sender As Object, _
       ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bw.DoWork

     Dim sFile As String = e.Argument

再次,一旦你有哈希关闭文件:

    md5.ComputeHash(f)
    f.Close()

不要打开任何表格。只需获取哈希即可。

    For Each hashByte In hash
        buff.Append(String.Format("{0:X1}", hashByte))
    Next

    thisHash = buff.ToString()       ' last line!!!

当 BackgroundWorker 完成时,它会引发一个事件:

Private Sub bw_RunWorkerCompleted(ByVal sender As Object, _
    ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) _
      Handles bw.RunWorkerCompleted

   ' I dont know why each file has to have its own form rather
   ' that a report item in a listbox but I also dont know why you
   ' are computing a hash for a 0 byte new file
    If thisHash = "D41D8CD98F0B24E980998ECF8427E" Then
        frm2 = New Form2
        frm2.Label1.Text = thisFile
        frm2.Show()
    End If

End Sub
End Class

要使用它,请在日志事件中使用一行代码:

  Dim fMgr As New FileMgr(e.FullPath)

Windows 报告的每个文件操作都会创建一个新的文件助手,它将运行自己的 BackgroundWorker。由于您没有做太多事情,因此在处理大于 0 字节的文件之前,一次不会有太多活动。当文件打开和使用时,您还需要在 MD5Sub/ProcessFile 中使用 Try/Catch。

我在监视文件夹中删除了 6 个文件,获得了 Form2 的 6 个副本,没有错误也没有冻结(甚至没有为这一切投票)。

于 2013-10-22T13:58:37.050 回答