AsyncUnbuffWriter.vb 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. Imports System.Threading
  2. Imports System.Net
  3. Imports System.Net.Sockets
  4. Imports System.IO
  5. Imports System.Collections.Concurrent
  6. Imports System.Reflection
  7. Imports System.Runtime.InteropServices
  8. Imports System.Diagnostics
  9. Imports System.Collections.Generic
  10. Public Class AsyncUnbuffWriter
  11. '''' We need the page size for best performance - so we use GetSystemInfo and dwPageSize
  12. ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  13. ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  14. Public Class clsSystemInfo
  15. private Class WinApi
  16. <DllImport("kernel32.dll")> _
  17. Public Shared Sub GetSystemInfo(<MarshalAs(UnmanagedType.Struct)> ByRef lpSystemInfo As SYSTEM_INFO)
  18. End Sub
  19. <StructLayout(LayoutKind.Sequential)> _
  20. Public Structure SYSTEM_INFO
  21. Friend uProcessorInfo As _PROCESSOR_INFO_UNION
  22. Public dwPageSize As UInteger
  23. Public lpMinimumApplicationAddress As IntPtr
  24. Public lpMaximumApplicationAddress As IntPtr
  25. Public dwActiveProcessorMask As IntPtr
  26. Public dwNumberOfProcessors As UInteger
  27. Public dwProcessorType As UInteger
  28. Public dwAllocationGranularity As UInteger
  29. Public dwProcessorLevel As UShort
  30. Public dwProcessorRevision As UShort
  31. End Structure
  32. <StructLayout(LayoutKind.Explicit)> _
  33. Public Structure _PROCESSOR_INFO_UNION
  34. <FieldOffset(0)> _
  35. Friend dwOemId As UInteger
  36. <FieldOffset(0)> _
  37. Friend wProcessorArchitecture As UShort
  38. <FieldOffset(2)> _
  39. Friend wReserved As UShort
  40. End Structure
  41. End Class
  42. Public Shared Function GetPageSize() As Integer
  43. Dim sysinfo As New WinApi.SYSTEM_INFO()
  44. WinApi.GetSystemInfo(sysinfo)
  45. Return CInt(sysinfo.dwPageSize)
  46. End Function
  47. End Class
  48. Private target As FileStream
  49. Private inputBuffer As MemoryStream
  50. Private bufferSize As Integer
  51. Private running As Boolean
  52. Private writing As Boolean
  53. Private readWait As Threading.ManualResetEvent
  54. Private writeWait As Threading.ManualResetEvent
  55. Private finishedWriting As Threading.ManualResetEvent
  56. Private totalWritten As Int64
  57. Private writeTimer As Stopwatch
  58. Public Function GetTotalBytesWritten() As Int64
  59. Return totalWritten
  60. End Function
  61. Public Function IsRunning() As Boolean
  62. Return running
  63. End Function
  64. Public Sub Close()
  65. writing = False
  66. writeWait .Set
  67. finishedWriting.WaitOne
  68. readWait .Set
  69. End Sub
  70. Public Function GetActiveMiliseconds() As Int64
  71. Try
  72. Return writeTimer.ElapsedMilliseconds
  73. Catch ex As Exception
  74. Return 0
  75. End Try
  76. End Function
  77. Public Shared Function GetPageSize() As Integer
  78. Return clsSystemInfo.GetPageSize
  79. End Function
  80. Public Sub new(ByVal dest As String, _
  81. Optional ByVal unbuffered As Boolean = False, _
  82. Optional ByVal _bufferSize As Integer = (1024 * 1024), _
  83. Optional ByVal setLength As Int64 = 0)
  84. bufferSize = _bufferSize
  85. Dim options As FileOptions = FileOptions.SequentialScan
  86. If unbuffered then options = FileOptions.WriteThrough or FileOptions.SequentialScan
  87. readWait = New Threading.ManualResetEvent(False)
  88. writeWait = New Threading.ManualResetEvent(False)
  89. finishedWriting = New Threading.ManualResetEvent(False)
  90. readWait .Set
  91. writeWait .Reset
  92. finishedWriting .Reset
  93. target = New FileStream(dest, _
  94. FileMode.Create, FileAccess.Write, FileShare.None, GetPageSize, options)
  95. If setLength > 0 then target.SetLength(setLength)
  96. totalWritten = 0
  97. inputBuffer = New MemoryStream(bufferSize)
  98. running = True
  99. writing = True
  100. writeTimer = New Stopwatch
  101. Dim asyncWriter As New Threading.Thread(AddressOf WriteThread)
  102. With asyncWriter
  103. .Priority = Threading.ThreadPriority.Lowest
  104. .IsBackground = True
  105. .Name = "AsyncCopy writer"
  106. .Start()
  107. End With
  108. End Sub
  109. Public Function Write(ByVal someBytes() As Byte, numToWrite As Integer) As Boolean
  110. If Not running then Return False
  111. If numToWrite < 1 then Return False
  112. If numToWrite > inputBuffer.Capacity then
  113. Throw New Exception("clsAsyncUnbuffWriter: someBytes() can not be larger then buffer capacity")
  114. End If
  115. If (inputBuffer.Length + numToWrite) > inputBuffer.Capacity then
  116. If inputBuffer.Length > 0 then
  117. readWait .Reset
  118. writeWait .Set
  119. readWait .WaitOne
  120. If Not running then Return False
  121. inputBuffer.Write(someBytes, 0, numToWrite)
  122. End If
  123. Else
  124. inputBuffer.Write(someBytes, 0, numToWrite)
  125. End If
  126. Return True
  127. End Function
  128. Private Sub WriteThread()
  129. Dim bytesThisTime As Int32 = 0
  130. Dim internalBuffer(bufferSize) As byte
  131. writeTimer .Stop
  132. writeTimer .Reset
  133. writeTimer .Start
  134. Do
  135. writeWait .WaitOne
  136. writeWait .Reset
  137. bytesThisTime = CInt(inputBuffer.Length)
  138. Buffer.BlockCopy(inputBuffer.GetBuffer, 0, internalBuffer, 0, bytesThisTime)
  139. inputBuffer .SetLength(0)
  140. readWait .Set()
  141. target.Write(internalBuffer, 0, bytesThisTime)
  142. totalWritten += bytesThisTime
  143. Loop While writing
  144. ' Flush inputBuffer
  145. If inputBuffer.Length > 0 then
  146. bytesThisTime = CInt(inputBuffer.Length)
  147. Buffer.BlockCopy(inputBuffer.GetBuffer, 0, internalBuffer, 0, bytesThisTime)
  148. target.Write(internalBuffer, 0, bytesThisTime)
  149. totalWritten += bytesThisTime
  150. End If
  151. running = False
  152. writeTimer .Stop
  153. Try
  154. target .Close
  155. target .Dispose
  156. Catch ex As Exception
  157. End Try
  158. inputBuffer .Close()
  159. finishedWriting .Set
  160. inputBuffer .Dispose()
  161. inputBuffer = Nothing
  162. internalBuffer = Nothing
  163. target = Nothing
  164. GC.GetTotalMemory(True)
  165. End Sub
  166. End Class