08-10-12, 05:44 PM
وهذا هو كود ال Component الخاص بنا:
المثال التالي يوضح كيفي استخدام ال Component السابق للقيام بنسخ عدة ملفات بشكل متتالي الواحد تلو الآخر:
طبعاً يمكنكم استخدام الأداة على تطبيق WPF أو حتى ASP.NET فقط كل ماعليك هو تعريف نسخة من ال Component السابق واستخدامه بالشكل المناسب لك.
كود :
Imports System.IO
Imports System.Threading
Imports System.ComponentModel
Imports System.Collections.Specialized
Public Class AsynchronousStreamCopy
Inherits Component
#Region "Events"
Public Custom Event StreamCopyProgressChanged As StreamCopyProgressChangedEventHandler
AddHandler(ByVal value As StreamCopyProgressChangedEventHandler)
SyncLock ChangedLock
Me.Events.AddHandler(ChangedLock, value)
End SyncLock
End AddHandler
RemoveHandler(ByVal value As StreamCopyProgressChangedEventHandler)
SyncLock ChangedLock
Me.Events.RemoveHandler(ChangedLock, value)
End SyncLock
End RemoveHandler
RaiseEvent(ByVal e As StreamCopyProgressChangedEventArgs)
Dim handler As StreamCopyProgressChangedEventHandler = Nothing
SyncLock ChangedLock
handler = Me.Events(ChangedLock)
End SyncLock
If handler IsNot Nothing Then
handler(e)
End If
End RaiseEvent
End Event
Public Custom Event StreamCopyCompleted As StreamCopyCompletedEventHandler
AddHandler(ByVal value As StreamCopyCompletedEventHandler)
SyncLock CompletedLock
Me.Events.AddHandler(CompletedLock, value)
End SyncLock
End AddHandler
RemoveHandler(ByVal value As StreamCopyCompletedEventHandler)
SyncLock CompletedLock
Me.Events.RemoveHandler(CompletedLock, value)
End SyncLock
End RemoveHandler
RaiseEvent(ByVal e As AsyncCompletedEventArgs)
Dim handler As StreamCopyCompletedEventHandler = Nothing
SyncLock CompletedLock
handler = Me.Events(CompletedLock)
End SyncLock
If handler IsNot Nothing Then
handler.Invoke(e)
End If
End RaiseEvent
End Event
#End Region
#Region "Delegates"
Private Delegate Sub Worker(ByVal container As StreamsContainer)
#End Region
#Region "Fields"
Private OnCopyCompletedDelegate As SendOrPostCallback
Private OnCopyProgressChangedDelegate As SendOrPostCallback
Protected TasksHash As New HybridDictionary
Private Const _defaultId As String = "Default"
Private ReadOnly _buffersize As Integer = &H1000
Private components As IContainer = Nothing
Private ReadOnly ChangedLock As New Object()
Private ReadOnly CompletedLock As New Object()
#End Region
#Region "Constructors"
Public Sub New()
MyBase.New()
InitializeDelegates()
End Sub
Public Sub New(ByVal container As IContainer)
Me.New()
container.Add(Me)
End Sub
Public Sub New(ByVal container As IContainer, ByVal buferrsize As Integer)
Me.New(container)
Me._buffersize = _buffersize
End Sub
Public Sub New(ByVal container As IContainer, ByVal buffersize As Integer, ByVal sc As SynchronizationContext)
Me.New(container, buffersize)
AsyncOperationManager.SynchronizationContext = sc
End Sub
Public Sub New(ByVal sc As SynchronizationContext)
Me.New()
AsyncOperationManager.SynchronizationContext = sc
End Sub
Public Sub New(ByVal buffersize As Integer)
Me.New()
Me._buffersize = buffersize
End Sub
Prvate Sub InitializeDelegates()
OnCopyCompletedDelegate = New SendOrPostCallback(AddressOf CopyCompleted)
OnCopyProgressChangedDelegate = New SendOrPostCallback(AddressOf CopyProgressChanged)
End Sub
#End Region
#Region "Methods"
Public Overloads Sub CopyStreamAsync(ByVal sourceStream As Stream, ByVal destinationStream As Stream)
CopyStreamAsync(sourceStream, destinationStream, _defaultId)
End Sub
Public Overloads Sub CopyStreamAsync(ByVal sourceStream As Stream _
, ByVal destination As Stream _
, ByVal taskId As Object)
Dim operation As AsyncOperation = AsyncOperationManager.CreateOperation(taskId)
SyncLock TasksHash.SyncRoot
If TasksHash.Contains(taskId) Then
If taskId Is _defaultId Then
Throw New InvalidOperationException("Worker is busy")
End If
Throw New Exception("Task already exists")
End If
TasksHash(TaskId) = operation
End SyncLock
Dim container As New StreamsContainer(sourceStream, destination, operation, _buffersize)
Dim worker As New Worker(AddressOf StartCopy)
worker.BeginInvoke(container, Nothing, Nothing)
End Sub
Private Function TaskExists(ByVal taskId As Object) As Boolean
Return Not TasksHash(taskId) Is Nothing
End Function
Private Sub StartCopy(ByVal container As StreamsContainer)
If TaskExists(container.Operation.UserSuppliedState) Then
Try
Dim source = container.SourceStream
source.BeginRead(container.Buffer, 0, container.Buffer.Length _
, New AsyncCallback(AddressOf ReadEnd), container)
Catch ex As Exception
Me.CompleteCopy(container, ex, False)
End Try
Else
Throw New InvalidOperationException("Task doesn't exist.")
End If
End Sub
Private Sub ReadEnd(ByVal results As IAsyncResult)
Dim container = CType(results.AsyncState, StreamsContainer)
Try
Dim read = container.SourceStream.EndRead(results)
container.Position += read
If TaskExists(container.Operation.UserSuppliedState) Then
If read = 0 Then
Me.CompleteCopy(container, Nothing, False)
Else
container.DestinationStream.BeginWrite( _
container.Buffer, 0, container.Buffer.Length, _
New AsyncCallback(AddressOf Me.WriteEnd), container)
End If
Else
Me.CompleteCopy(container, Nothing, True)
End If
Catch ex As Exception
Me.CompleteCopy(container, ex, False)
End Try
End Sub
Private Sub WriteEnd(ByVal results As IAsyncResult)
Dim container = CType(results.AsyncState, StreamsContainer)
If TaskExists(container.Operation.UserSuppliedState) Then
Try
container.DestinationStream.EndWrite(results)
Dim percentage As Integer = _
container.Position / container.SourceStream.Length * 100
Dim e As New StreamCopyProgressChangedEventArgs(container.Position _
, container.Operation.UserSuppliedState, percentage)
container.Operation.Post(OnCopyProgressChangedDelegate, e)
container.SourceStream.BeginRead(container.Buffer, _
0, container.Buffer.Length, _
New AsyncCallback(AddressOf Me.ReadEnd), container)
Catch ex As Exception
Me.CompleteCopy(container, ex, False)
End Try
Else
Me.CompleteCopy(container, Nothing, True)
End If
End Sub
Private Sub CompleteCopy(ByVal container As StreamsContainer _
, ByVal exc As Exception _
, ByVal canceled As Boolean)
SyncLock TasksHash.SyncRoot
If TaskExists(container.Operation.UserSuppliedState) Then
TasksHash.Remove(container.Operation.UserSuppliedState)
End If
End SyncLock
Dim e As New AsyncCompletedEventArgs(exc, _
canceled, container.Operation.UserSuppliedState)
container.Operation.PostOperationCompleted(OnCopyCompletedDelegate, e)
End Sub
Private Sub CopyCompleted(ByVal e As AsyncCompletedEventArgs)
OnCopyProgressCompleted(e)
End Sub
Private Sub CopyProgressChanged(ByVal e As StreamCopyProgressChangedEventArgs)
OnCopyProgressChanged(e)
End Sub
Protected Overridable Sub OnCopyProgressChanged(ByVal e As StreamCopyProgressChangedEventArgs)
RaiseEvent StreamCopyProgressChanged(e)
End Sub
Protected Overridable Sub OnCopyProgressCompleted(ByVal e As AsyncCompletedEventArgs)
RaiseEvent StreamCopyCompleted(e)
End Sub
Public Overloads Sub CancelAsync()
CancelAsync(_defaultId)
End Sub
Public Overloads Sub CancelAsync(ByVal userState As Object)
If userstate Is Nothing Then
Throw New ArgumentNullException("userState")
End If
If Not TaskExists(userstate) Then
Throw New ArgumentException("userState doesn't exist.")
End If
SyncLock TasksHash
TasksHash.Remove(userstate)
End SyncLock
End Sub
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If Not components Is Nothing Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub
#End Region
#Region "Properties"
Public ReadOnly Property BufferSize() As Integer
Get
Return _buffersize
End Get
End Property
#End Region
End Classكود :
Imports StreamCopyAsync
Imports System.ComponentModel
Imports System.Windows
Imports System.IO
Imports System.Threading
Public Class Form1
Dim mre As ManualResetEvent
Private Sub _AsyncCopy_StreamCopyCompleted(ByVal e As AsyncCompletedEventArgs) Handles _AsyncCopy.StreamCopyCompleted
If e.Error IsNot Nothing Then
MessageBox.Show(e.Error.Message)
Me.lblStatus.Text = "Copy was not successful."
ElseIf e.Cancelled Then
Me.lblStatus.Text = "Copy canceled."
Else
Me.lblStatus.Text = "Copy completed successfully."
End If
If Not mre.SafeWaitHandle.IsClosed Then
mre.Set()
End If
End Sub
Private Sub _AsyncCopy_StreamCopyProgressChanged(ByVal e As StreamCopyProgressChangedEventArgs) Handles _AsyncCopy.StreamCopyProgressChanged
Me.ProgressBar1.Value = e.ProgressPercentage
Me.lblStatus.Text = e.BytesCopied & " bytes copied. Total progress: " & e.ProgressPercentage & " %"
End Sub
Private Sub BtnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnstart.Click
ThreadPool.QueueUserWorkItem(AddressOf StartCopy)
End Sub
Private Sub BtnCancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btncancel.Click
_AsyncCopy.CancelAsync()
mre.Reset();
mre.Dispose()
End Sub
Sub StartCopy()
Dim Sources As IEnumerable(Of FileStream) = _
My.Computer.FileSystem.GetFiles("D:") _
.Select(Function(x) File.OpenRead(x))
Dim destination As IEnumerable(Of FileStream) = _
My.Computer.FileSystem.GetFiles("D:") _
.Select(Function(x) File.OpenWrite(x.Replace("D:\", "D:\Copy of ")))
mre = New Semaphore(False)
Using SourceEnum = Sources.GetEnumerator, _
DestnationEnum = destination.GetEnumerator
While SourceEnum.MoveNext AndAlso DestnationEnum.MoveNext
Using CurrentSource = SourceEnum.Current, _
CurrentDest = DestnationEnum.Current
_AsyncCopy.CopyStreamAsync(SourceEnum.Current, DestnationEnum.Current)
mre.Dispose()
End Using
End While
End Using
sema = Nothing
End Sub
End Class