Advertisement
Guest User

FileSplitter in VB.Net, by ElektroStudios

a guest
May 27th, 2015
130
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
VB.NET 38.71 KB | None | 0 0
  1.  
  2. ' ***********************************************************************
  3. ' Author           : Elektro
  4. ' Last Modified On : 28-May-2015
  5. ' ***********************************************************************
  6. ' <copyright file="FileSplitter.vb" company="Elektro Studios">
  7. '     Copyright (c) Elektro Studios. All rights reserved.
  8. ' </copyright>
  9. ' ***********************************************************************
  10.  
  11. #Region " Usage Examples "
  12.  
  13. 'Public NotInheritable Class Form1
  14.  
  15. '    ''' <summary>
  16. '    ''' Handles the <see cref="FileSplitter"/> instance.
  17. '    ''' </summary>
  18. '    Private WithEvents splitter As New FileSplitter() With {.BufferSize = .BufferSize}
  19.  
  20. '    ' Splitter settings.
  21. '    Private ReadOnly workingDir As String = "C:\Test"
  22. '    Private ReadOnly fileName As String = "File.txt"
  23. '    Private ReadOnly filePath As String = IO.Path.Combine(workingDir, fileName)
  24. '    Private ReadOnly chunkName As String = "File.Part"
  25. '    Private ReadOnly chunkExt As String = "fs"
  26.  
  27. '    ' Merger settings.
  28. '    Private ReadOnly firstChunkPath As String = String.Format("{0}\{1}.01.{2}", workingDir, chunkName, chunkExt)
  29. '    Private ReadOnly targetFileName As String = String.Format("{0}\{1}.{2}", workingDir, "Merged", IO.Path.GetExtension(fileName))
  30.  
  31. '    ' Some default chunk sizes to split a file.
  32. '    Private ReadOnly kilobyte As Integer = 1024
  33. '    Private ReadOnly megabyte As Integer = 1048576
  34. '    Private ReadOnly gigabyte As Integer = 1073741824
  35. '    Private ReadOnly halfFileSize As Integer = CInt(New IO.FileInfo(filePath).Length / 2)
  36.  
  37. '    ' The label controls that will display the progress.
  38. '    Private labelSplit1, labelSplit2, labelSplit3 As New Label
  39. '    Private labelMerge1, labelMerge2, labelMerge3 As New Label
  40.  
  41. '    ' The button controls to start a split or merge operation.
  42. '    Private WithEvents buttonSplit, buttonMerge As New Button
  43.  
  44. '    ''' <summary>
  45. '    ''' Initializes a new instance of the <see cref="Form1"/> class.
  46. '    ''' </summary>
  47. '    Public Sub New()
  48.  
  49. '        ' This call is required by the designer.
  50. '        Me.InitializeComponent()
  51.  
  52. '        ' Set the controls properties.
  53. '        With buttonSplit
  54. '            .Text = "Split"
  55. '            .Font = New Font(Me.Font.FontFamily, 14.0F, FontStyle.Bold)
  56. '            .Size = New Size(200, 75)
  57. '            .Location = New Point(0, 0)
  58. '            .Cursor = Cursors.Hand
  59. '        End With
  60.  
  61. '        With buttonMerge
  62. '            .Text = "Merge"
  63. '            .Font = New Font(Me.Font.FontFamily, 14.0F, FontStyle.Bold)
  64. '            .Size = New Size(200, 75)
  65. '            .Location = New Point(buttonSplit.Location.X + buttonSplit.Width, 0)
  66. '            .Cursor = Cursors.Hand
  67. '        End With
  68.  
  69. '        With labelSplit1
  70. '            .Text = "Total Progress:"
  71. '            .AutoSize = True
  72. '            .Font = New Font(Me.Font.FontFamily, 9.0F, FontStyle.Regular)
  73. '            .Location = New Point(0, buttonSplit.Location.Y + buttonSplit.Height + 10)
  74. '        End With
  75.  
  76. '        With labelSplit2
  77. '            .Text = "Chunk Progress:"
  78. '            .AutoSize = True
  79. '            .Font = New Font(Me.Font.FontFamily, 9.0F, FontStyle.Regular)
  80. '            .Location = New Point(0, labelSplit1.Location.Y + labelSplit1.Height)
  81. '        End With
  82.  
  83. '        With labelSplit3
  84. '            .Text = "Chunk Count:"
  85. '            .AutoSize = True
  86. '            .Font = New Font(Me.Font.FontFamily, 9.0F, FontStyle.Regular)
  87. '            .Location = New Point(0, labelSplit2.Location.Y + labelSplit2.Height)
  88. '        End With
  89.  
  90. '        With labelMerge1
  91. '            .Text = "Total Progress:"
  92. '            .AutoSize = True
  93. '            .Font = New Font(Me.Font.FontFamily, 9.0F, FontStyle.Regular)
  94. '            .Location = New Point(buttonMerge.Location.X, buttonMerge.Location.Y + buttonMerge.Height + 10)
  95. '        End With
  96.  
  97. '        With labelMerge2
  98. '            .Text = "Chunk Progress:"
  99. '            .AutoSize = True
  100. '            .Font = New Font(Me.Font.FontFamily, 9.0F, FontStyle.Regular)
  101. '            .Location = New Point(buttonMerge.Location.X, labelMerge1.Location.Y + labelMerge1.Height)
  102. '        End With
  103.  
  104. '        With labelMerge3
  105. '            .Text = "Chunk Count:"
  106. '            .AutoSize = True
  107. '            .Font = New Font(Me.Font.FontFamily, 9.0F, FontStyle.Regular)
  108. '            .Location = New Point(buttonMerge.Location.X, labelMerge2.Location.Y + labelMerge2.Height)
  109. '        End With
  110.  
  111. '        ' Add the controls on the UI.
  112.         'Me.Controls.AddRange({labelSplit1, labelSplit2, labelSplit3,
  113. '                              labelMerge1, labelMerge2, labelMerge3,
  114. '                              buttonSplit, buttonMerge})
  115.  
  116. '        ' Set the Form properties.
  117. '        With Me
  118. '            .Size = New Size(buttonSplit.Width + buttonMerge.Width + 20, 200)
  119. '            .FormBorderStyle = Windows.Forms.FormBorderStyle.FixedDialog
  120. '            .MaximizeBox = False
  121. '        End With
  122.  
  123. '    End Sub
  124.  
  125. '    ''' <summary>
  126. '    ''' Handles the <see cref="Button.Click"/> event of the <see cref="ButtonSplit"/> control.
  127. '    ''' </summary>
  128. '    Private Sub ButtonSplit_Click() Handles buttonSplit.Click
  129.  
  130. '        Me.splitter.Split(sourceFile:=Me.filePath,
  131. '                          chunkSize:=Me.halfFileSize,
  132. '                          chunkName:=Me.chunkName,
  133. '                          chunkExt:=Me.chunkExt,
  134. '                          overwrite:=True,
  135. '                          deleteAfterSplit:=False)
  136.  
  137. '        ' Or...
  138. '        'Me.splitter.Split(sourceFile:=Me.filePath,
  139. '        '                  chunkCount:=2,
  140. '        '                  chunkName:=Me.chunkName,
  141. '        '                  chunkExt:=Me.chunkExt,
  142. '        '                  overwrite:=True,
  143. '        '                  deleteAfterSplit:=False)
  144. '    End Sub
  145.  
  146. '    ''' <summary>
  147. '    ''' Handles the <see cref="Button.Click"/> event of the <see cref="ButtonMerge"/> control.
  148. '    ''' </summary>
  149. '    Private Sub ButtonMerge_Click() Handles buttonMerge.Click
  150.  
  151. '        Me.splitter.Merge(sourceChunk:=Me.firstChunkPath,
  152. '                          targetFile:=Me.targetFileName,
  153. '                          overwrite:=True,
  154. '                          deleteChunksAfterMerged:=False)
  155.  
  156. '    End Sub
  157.  
  158. '    ''' <summary>
  159. '    ''' Handles the <see cref="FileSplitter.SplitProgressChangedArgs"/> event of the <see cref="Splitter"/> instance.
  160. '    ''' </summary>
  161. '    ''' <param name="sender">The source of the event.</param>
  162. '    ''' <param name="e">The <see cref="FileSplitter.SplitProgressChangedArgs"/> instance containing the event data.</param>
  163. '    Private Sub Splitter_SplitProgressChangedArgs(ByVal sender As Object, ByVal e As FileSplitter.SplitProgressChangedArgs) _
  164. '    Handles splitter.SplitProgressChanged
  165.  
  166. '        labelSplit1.Text = String.Format("Total Progress: {0}%", e.TotalProgress.ToString("n1"))
  167. '        labelSplit2.Text = String.Format("Chunk Progress: {0}%", e.ChunkProgress.ToString("n1"))
  168. '        labelSplit3.Text = String.Format("Current  Chunk: {0} of {1}", CStr(e.ChunksCreated + 1), CStr(e.ChunksToCreate))
  169. '        Application.DoEvents()
  170.  
  171. '    End Sub
  172.  
  173. '    ''' <summary>
  174. '    ''' Handles the <see cref="FileSplitter.MergeProgressChangedArgs"/> event of the <see cref="Splitter"/> instance.
  175. '    ''' </summary>
  176. '    ''' <param name="sender">The source of the event.</param>
  177. '    ''' <param name="e">The <see cref="FileSplitter.MergeProgressChangedArgs"/> instance containing the event data.</param>
  178. '    Private Sub Splitter_MergeProgressChangedArgs(ByVal sender As Object, ByVal e As FileSplitter.MergeProgressChangedArgs) _
  179. '    Handles splitter.MergeProgressChanged
  180.  
  181. '        labelMerge1.Text = String.Format("Total Progress: {0}%", e.TotalProgress.ToString("n1"))
  182. '        labelMerge2.Text = String.Format("Chunk Progress: {0}%", e.ChunkProgress.ToString("n1"))
  183. '        labelMerge3.Text = String.Format("Current  Chunk: {0} of {1}", CStr(e.ChunksMerged + 1), CStr(e.ChunksToMerge))
  184. '        Application.DoEvents()
  185.  
  186. '    End Sub
  187.  
  188. 'End Class
  189.  
  190. #End Region
  191.  
  192. #Region " Option Statements "
  193.  
  194. Option Strict On
  195. Option Explicit On
  196. Option Infer Off
  197.  
  198. #End Region
  199.  
  200. #Region " Imports "
  201.  
  202. Imports System.ComponentModel
  203. Imports System.IO
  204.  
  205. #End Region
  206.  
  207. ''' <summary>
  208. ''' Splits a file into manageable chunks, or merge the splitted chunks.
  209. ''' With progress-percent features.
  210. ''' </summary>
  211. Public NotInheritable Class FileSplitter
  212.  
  213. #Region " Properties "
  214.  
  215.     ''' <summary>
  216.     ''' Gets or sets the buffer-size used to split or merge, in Bytes.
  217.     ''' Default value is: 524288 bytes (512 Kb).
  218.     ''' </summary>
  219.     ''' <value>The buffer-size.</value>
  220.     Public Property BufferSize As Integer = 524288
  221.     '    4096 Bytes (  4 Kb) This is the default Microsoft's FileStream implementation buffer size.
  222.     '    8192 Bytes (  8 Kb)
  223.     '   16384 Bytes ( 16 Kb)
  224.     '   32768 Bytes ( 32 Kb)
  225.     '   65536 Bytes ( 64 Kb)
  226.     '  131072 Bytes (128 Kb)
  227.     '  262144 Bytes (256 Kb)
  228.     '  524288 Bytes (512 Kb)
  229.     ' 1048576 Bytes (  1 Mb)
  230.  
  231. #End Region
  232.  
  233. #Region " Events "
  234.  
  235. #Region " Event Declarations "
  236.  
  237.     ''' <summary>
  238.     ''' Occurs when the progress changes when splitting a file.
  239.     ''' </summary>
  240.     Public Event SplitProgressChanged As EventHandler(Of SplitProgressChangedArgs)
  241.  
  242.     ''' <summary>
  243.     ''' Occurs when the progress changes when merging a file.
  244.     ''' </summary>
  245.     Public Event MergeProgressChanged As EventHandler(Of MergeProgressChangedArgs)
  246.  
  247. #End Region
  248.  
  249. #Region " Event Data "
  250.  
  251. #Region " SplitProgressChanged "
  252.  
  253.     ''' <summary>
  254.     ''' Contains the event data of the <see cref="FileSplitter.SplitProgressChanged"/> event.
  255.     ''' </summary>
  256.     Public NotInheritable Class SplitProgressChangedArgs : Inherits EventArgs
  257.  
  258. #Region " Properties "
  259.  
  260.         ''' <summary>
  261.         ''' Gets the total progress value.
  262.         ''' (From 0 to 100)
  263.         ''' </summary>
  264.         ''' <value>The total progress value.</value>
  265.         Public ReadOnly Property TotalProgress As Double
  266.             Get
  267.                 Return Me.totalProgress1
  268.             End Get
  269.         End Property
  270.         ''' <summary>
  271.         ''' The total progress value.
  272.         ''' (From 0 to 100)
  273.         ''' </summary>
  274.         Private ReadOnly totalProgress1 As Double = 0.0R
  275.  
  276.         ''' <summary>
  277.         ''' Gets the current chunk progress value.
  278.         ''' (From 0 to 100)
  279.         ''' </summary>
  280.         ''' <value>The current chunk progress value.</value>
  281.         Public ReadOnly Property ChunkProgress As Double
  282.             Get
  283.                 Return Me.chunkProgress1
  284.             End Get
  285.         End Property
  286.         ''' <summary>
  287.         ''' The current chunk progress value.
  288.         ''' (From 0 to 100)
  289.         ''' </summary>
  290.         Private ReadOnly chunkProgress1 As Double = 0.0R
  291.  
  292.         ''' <summary>
  293.         ''' Gets the amount of chunks to create.
  294.         ''' </summary>
  295.         ''' <value>The amount of chunks to create.</value>
  296.         Public ReadOnly Property ChunksToCreate As Long
  297.             Get
  298.                 Return Me.chunksToCreate1
  299.             End Get
  300.         End Property
  301.         ''' <summary>
  302.         ''' The amount of chunks to create.
  303.         ''' </summary>
  304.         Private ReadOnly chunksToCreate1 As Long = 0L
  305.  
  306.         ''' <summary>
  307.         ''' Gets the amount of created chunks.
  308.         ''' </summary>
  309.         ''' <value>The amount of created chunks.</value>
  310.         Public ReadOnly Property ChunksCreated As Long
  311.             Get
  312.                 Return Me.chunksCreated1
  313.             End Get
  314.         End Property
  315.         ''' <summary>
  316.         ''' The amount of created chunks.
  317.         ''' </summary>
  318.         Private ReadOnly chunksCreated1 As Long = 0L
  319.  
  320. #End Region
  321.  
  322. #Region " Constructors "
  323.  
  324.         ''' <summary>
  325.         ''' Prevents a default instance of the <see cref="FileSplitter.SplitProgressChangedArgs"/> class from being created.
  326.         ''' </summary>
  327.         Private Sub New()
  328.         End Sub
  329.  
  330.         ''' <summary>
  331.         ''' Initializes a new instance of the <see cref="FileSplitter.SplitProgressChangedArgs"/> class.
  332.         ''' </summary>
  333.         ''' <param name="totalProgress">The total progress value.</param>
  334.         ''' <param name="chunkProgress">The current chunk progress value.</param>
  335.         ''' <param name="chunksToCreate">The amount of chunks to create.</param>
  336.         ''' <param name="chunksCreated">The amount of created chunks.</param>
  337.         Public Sub New(ByVal totalProgress As Double,
  338.                        ByVal chunkProgress As Double,
  339.                        ByVal chunksToCreate As Long,
  340.                        ByVal chunksCreated As Long)
  341.  
  342.             Me.totalProgress1 = totalProgress
  343.             Me.chunkProgress1 = chunkProgress
  344.             Me.chunksToCreate1 = chunksToCreate
  345.             Me.chunksCreated1 = chunksCreated
  346.  
  347.         End Sub
  348.  
  349. #End Region
  350.  
  351. #Region " Hidden Methods "
  352.  
  353.         ''' <summary>
  354.         ''' Serves as a hash function for a particular type.
  355.         ''' </summary>
  356.         <EditorBrowsable(EditorBrowsableState.Never)>
  357.         Public Shadows Function GetHashCode() As Integer
  358.             Return MyBase.GetHashCode
  359.         End Function
  360.  
  361.         ''' <summary>
  362.         ''' Gets the System.Type of the current instance.
  363.         ''' </summary>
  364.         ''' <returns>The exact runtime type of the current instance.</returns>
  365.         <EditorBrowsable(EditorBrowsableState.Never)>
  366.         Public Shadows Function [GetType]() As Type
  367.             Return MyBase.GetType
  368.         End Function
  369.  
  370.         ''' <summary>
  371.         ''' Determines whether the specified System.Object instances are considered equal.
  372.         ''' </summary>
  373.         <EditorBrowsable(EditorBrowsableState.Never)>
  374.         Public Shadows Function Equals(ByVal obj As Object) As Boolean
  375.             Return MyBase.Equals(obj)
  376.         End Function
  377.  
  378.         ''' <summary>
  379.         ''' Determines whether the specified System.Object instances are the same instance.
  380.         ''' </summary>
  381.         <EditorBrowsable(EditorBrowsableState.Never)>
  382.         Private Shadows Function ReferenceEquals(ByVal objA As Object, ByVal objB As Object) As Boolean
  383.             Return Nothing
  384.         End Function
  385.  
  386.         ''' <summary>
  387.         ''' Returns a String that represents the current object.
  388.         ''' </summary>
  389.         <EditorBrowsable(EditorBrowsableState.Never)>
  390.         Public Shadows Function ToString() As String
  391.             Return MyBase.ToString
  392.         End Function
  393.  
  394. #End Region
  395.  
  396.     End Class
  397.  
  398. #End Region
  399.  
  400. #Region " MergeProgressChangedArgs "
  401.  
  402.     ''' <summary>
  403.     ''' Contains the event data of the <see cref="FileSplitter.MergeProgressChanged"/> event.
  404.     ''' </summary>
  405.     Public NotInheritable Class MergeProgressChangedArgs : Inherits EventArgs
  406.  
  407. #Region " Properties "
  408.  
  409.         ''' <summary>
  410.         ''' Gets the total progress value.
  411.         ''' (From 0 to 100)
  412.         ''' </summary>
  413.         ''' <value>The total progress value.</value>
  414.         Public ReadOnly Property TotalProgress As Double
  415.             Get
  416.                 Return Me.totalProgress1
  417.             End Get
  418.         End Property
  419.         ''' <summary>
  420.         ''' The total progress value.
  421.         ''' (From 0 to 100)
  422.         ''' </summary>
  423.         Private ReadOnly totalProgress1 As Double = 0.0R
  424.  
  425.         ''' <summary>
  426.         ''' Gets the current chunk progress value.
  427.         ''' (From 0 to 100)
  428.         ''' </summary>
  429.         ''' <value>The current chunk progress value.</value>
  430.         Public ReadOnly Property ChunkProgress As Double
  431.             Get
  432.                 Return Me.chunkProgress1
  433.             End Get
  434.         End Property
  435.         ''' <summary>
  436.         ''' The current chunk progress value.
  437.         ''' (From 0 to 100)
  438.         ''' </summary>
  439.         Private ReadOnly chunkProgress1 As Double = 0.0R
  440.  
  441.         ''' <summary>
  442.         ''' Gets the amount of chunks to merge.
  443.         ''' </summary>
  444.         ''' <value>The amount of chunks to merge.</value>
  445.         Public ReadOnly Property ChunksToMerge As Long
  446.             Get
  447.                 Return Me.chunksToMerge1
  448.             End Get
  449.         End Property
  450.         ''' <summary>
  451.         ''' The amount of chunks to merge.
  452.         ''' </summary>
  453.         Private ReadOnly chunksToMerge1 As Long = 0L
  454.  
  455.         ''' <summary>
  456.         ''' Gets the amount of merged chunks.
  457.         ''' </summary>
  458.         ''' <value>The amount of merged chunks.</value>
  459.         Public ReadOnly Property ChunksMerged As Long
  460.             Get
  461.                 Return Me.chunksMerged1
  462.             End Get
  463.         End Property
  464.         ''' <summary>
  465.         ''' The amount of merged chunks.
  466.         ''' </summary>
  467.         Private ReadOnly chunksMerged1 As Long = 0L
  468.  
  469. #End Region
  470.  
  471. #Region " Constructors "
  472.  
  473.         ''' <summary>
  474.         ''' Prevents a default instance of the <see cref="FileSplitter.MergeProgressChangedArgs"/> class from being created.
  475.         ''' </summary>
  476.         Private Sub New()
  477.         End Sub
  478.  
  479.         ''' <summary>
  480.         ''' Initializes a new instance of the <see cref="FileSplitter.MergeProgressChangedArgs"/> class.
  481.         ''' </summary>
  482.         ''' <param name="totalProgress">The total progress value.</param>
  483.         ''' <param name="chunkProgress">The current chunk progress value.</param>
  484.         ''' <param name="chunksToMerge">The amount of chunks to merge.</param>
  485.         ''' <param name="chunksMerged">The amount of merged chunks.</param>
  486.         Public Sub New(ByVal totalProgress As Double,
  487.                        ByVal chunkProgress As Double,
  488.                        ByVal chunksToMerge As Long,
  489.                        ByVal chunksMerged As Long)
  490.  
  491.             Me.totalProgress1 = totalProgress
  492.             Me.chunkProgress1 = chunkProgress
  493.             Me.chunksToMerge1 = chunksToMerge
  494.             Me.chunksMerged1 = chunksMerged
  495.  
  496.         End Sub
  497.  
  498. #End Region
  499.  
  500. #Region " Hidden Methods "
  501.  
  502.         ''' <summary>
  503.         ''' Serves as a hash function for a particular type.
  504.         ''' </summary>
  505.         <EditorBrowsable(EditorBrowsableState.Never)>
  506.         Public Shadows Function GetHashCode() As Integer
  507.             Return MyBase.GetHashCode
  508.         End Function
  509.  
  510.         ''' <summary>
  511.         ''' Gets the System.Type of the current instance.
  512.         ''' </summary>
  513.         ''' <returns>The exact runtime type of the current instance.</returns>
  514.         <EditorBrowsable(EditorBrowsableState.Never)>
  515.         Public Shadows Function [GetType]() As Type
  516.             Return MyBase.GetType
  517.         End Function
  518.  
  519.         ''' <summary>
  520.         ''' Determines whether the specified System.Object instances are considered equal.
  521.         ''' </summary>
  522.         <EditorBrowsable(EditorBrowsableState.Never)>
  523.         Public Shadows Function Equals(ByVal obj As Object) As Boolean
  524.             Return MyBase.Equals(obj)
  525.         End Function
  526.  
  527.         ''' <summary>
  528.         ''' Determines whether the specified System.Object instances are the same instance.
  529.         ''' </summary>
  530.         <EditorBrowsable(EditorBrowsableState.Never)>
  531.         Private Shadows Function ReferenceEquals(ByVal objA As Object, ByVal objB As Object) As Boolean
  532.             Return Nothing
  533.         End Function
  534.  
  535.         ''' <summary>
  536.         ''' Returns a String that represents the current object.
  537.         ''' </summary>
  538.         <EditorBrowsable(EditorBrowsableState.Never)>
  539.         Public Shadows Function ToString() As String
  540.             Return MyBase.ToString
  541.         End Function
  542.  
  543. #End Region
  544.  
  545.     End Class
  546.  
  547. #End Region
  548.  
  549. #End Region
  550.  
  551. #End Region
  552.  
  553. #Region " Public Methods "
  554.  
  555.     ''' <summary>
  556.     ''' Splits a file into manageable chunks.
  557.     ''' </summary>
  558.     ''' <param name="sourceFile">The file to split.</param>
  559.     ''' <param name="chunkCount">The amount of chunks.</param>
  560.     ''' <param name="chunkName">The name formatting for chunks.</param>
  561.     ''' <param name="chunkExt">The file-extension for chunks.</param>
  562.     ''' <param name="overwrite">If set to <c>True</c>, any existing file will be overwritten if needed to create a chunk, otherwise, an exception will be thrown.</param>
  563.     ''' <param name="deleteAfterSplit">If set to <c>True</c>, the input file will be deleted after a successful split operation.</param>
  564.     ''' <exception cref="System.Exception"></exception>
  565.     Public Sub Split(ByVal sourceFile As String,
  566.                      ByVal chunkCount As Integer,
  567.                      Optional ByVal chunkName As String = Nothing,
  568.                      Optional ByVal chunkExt As String = Nothing,
  569.                      Optional ByVal overwrite As Boolean = False,
  570.                      Optional ByVal deleteAfterSplit As Boolean = False)
  571.  
  572.         Dim chunkSize As Long
  573.         Try
  574.             chunkSize = CLng(Math.Ceiling(New FileInfo(sourceFile).Length / chunkCount))
  575.  
  576.         Catch ex As Exception
  577.             Throw
  578.  
  579.         End Try
  580.  
  581.         Me.Split(sourceFile:=sourceFile,
  582.                  chunkSize:=chunkSize,
  583.                  chunkName:=chunkName,
  584.                  chunkExt:=chunkExt,
  585.                  overwrite:=overwrite,
  586.                  deleteAfterSplit:=deleteAfterSplit)
  587.  
  588.     End Sub
  589.  
  590.     ''' <summary>
  591.     ''' Splits a file into manageable chunks.
  592.     ''' </summary>
  593.     ''' <param name="sourceFile">The file to split.</param>
  594.     ''' <param name="chunkSize">The size per chunk.</param>
  595.     ''' <param name="chunkName">The name formatting for chunks.</param>
  596.     ''' <param name="chunkExt">The file-extension for chunks.</param>
  597.     ''' <param name="overwrite">If set to <c>True</c>, any existing file will be overwritten if needed to create a chunk, otherwise, an exception will be thrown.</param>
  598.     ''' <param name="deleteAfterSplit">If set to <c>True</c>, the input file will be deleted after a successful split operation.</param>
  599.     ''' <exception cref="System.IO.FileNotFoundException">The specified source file doesn't exists.</exception>
  600.     ''' <exception cref="System.IO.IOException">File already exists.</exception>
  601.     ''' <exception cref="System.OverflowException">'chunkSize' value should be smaller than the source filesize.</exception>
  602.     Public Sub Split(ByVal sourceFile As String,
  603.                      ByVal chunkSize As Long,
  604.                      Optional ByVal chunkName As String = Nothing,
  605.                      Optional ByVal chunkExt As String = Nothing,
  606.                      Optional ByVal overwrite As Boolean = False,
  607.                      Optional ByVal deleteAfterSplit As Boolean = False)
  608.  
  609.         If Not File.Exists(sourceFile) Then
  610.             Throw New FileNotFoundException("The specified source file doesn't exists.", sourceFile)
  611.             Exit Sub
  612.         End If
  613.  
  614.         ' The progress event arguments.
  615.         Dim progressArguments As SplitProgressChangedArgs
  616.  
  617.         ' FileInfo instance of the source file.
  618.         Dim fInfo As New FileInfo(sourceFile)
  619.  
  620.         ' The total filesize to split, in bytes.
  621.         Dim totalSize As Long = fInfo.Length
  622.  
  623.         ' The remaining size to calculate the percentage, in bytes.
  624.         Dim sizeRemaining As Long = totalSize
  625.  
  626.         ' Counts the length of the current chunk file to calculate the percentage, in bytes.
  627.         Dim sizeWritten As Long
  628.  
  629.         ' The buffer to read data and write the chunks.
  630.         Dim buffer As Byte()
  631.  
  632.         ' The buffer length.
  633.         Dim bufferLength As Integer
  634.  
  635.         ' The total amount of chunks to create.
  636.         Dim chunkCount As Long = CLng(Math.Ceiling((fInfo.Length) / (chunkSize)))
  637.  
  638.         ' Keeps track of the current chunk.
  639.         Dim chunkIndex As Long
  640.  
  641.         ' Keeps track of the amount of buffer-writting operations.
  642.         Dim writeCounts As Integer
  643.  
  644.         ' Keeps track of the current buffer-writting operation.
  645.         Dim writeCount As Integer
  646.  
  647.         ' Keeps track of the total percentage done.
  648.         Dim totalProgress As Double
  649.  
  650.         ' Keeps track of the current chunk percentage done.
  651.         Dim chunkProgress As Double
  652.  
  653.         ' A zero-filled string to enumerate the chunk parts.
  654.         Dim fileEnumeration As String
  655.  
  656.         ' The chunks filename.
  657.         Dim chunkFilename As String
  658.  
  659.         ' The chunks basename.
  660.         chunkName = If(String.IsNullOrEmpty(chunkName),
  661.                        Path.Combine(fInfo.DirectoryName, Path.GetFileNameWithoutExtension(fInfo.Name)),
  662.                        Path.Combine(fInfo.DirectoryName, chunkName))
  663.  
  664.         ' The chunks file extension.
  665.         chunkExt = If(String.IsNullOrEmpty(chunkExt),
  666.                       fInfo.Extension.Substring(1),
  667.                       chunkExt)
  668.  
  669.         Select Case chunkSize ' Set buffer size and calculate chunk count.
  670.  
  671.             Case Is >= fInfo.Length ' chunk size is bigger than source-file size.
  672.                 Throw New OverflowException("'chunkSize' value should be smaller than the source filesize.")
  673.                 Exit Sub
  674.  
  675.             Case Is < Me.BufferSize ' chunk size is smaller than buffer size.
  676.                 bufferLength = CInt(chunkSize)
  677.  
  678.             Case Else ' chunk size is bigger than buffer size.
  679.                 bufferLength = Me.BufferSize
  680.  
  681.         End Select ' chunkSize
  682.  
  683.         If Not overwrite Then ' If not file overwriting is allowed then...
  684.  
  685.             For index As Long = 1L To chunkCount ' Start index based on 1 (eg. "File.Part.1.ext").
  686.  
  687.                 ' Set chunk filename.
  688.                 fileEnumeration = New String("0"c, CStr(chunkCount).Length - CStr(index).Length)
  689.                 chunkFilename = String.Format("{0}.{1}.{2}", chunkName, fileEnumeration & CStr(index), chunkExt)
  690.  
  691.                 ' If chunk file already exists then...
  692.                 If File.Exists(chunkFilename) Then
  693.                     Throw New IOException(String.Format("File already exists: {0}", chunkFilename))
  694.                     Exit Sub
  695.                 End If
  696.  
  697.             Next index
  698.  
  699.         End If ' overwrite
  700.  
  701.         ' Open the file to start reading bytes.
  702.         Using inputStream As New FileStream(fInfo.FullName, FileMode.Open)
  703.  
  704.             Using binaryReader As New BinaryReader(inputStream)
  705.  
  706.                 While (inputStream.Position < inputStream.Length)
  707.  
  708.                     ' Increment the chunk file counter.
  709.                     chunkIndex += 1L
  710.  
  711.                     ' Set chunk filename.
  712.                     fileEnumeration = New String("0"c, CStr(chunkCount).Length - CStr(chunkIndex).Length)
  713.                     chunkFilename = String.Format("{0}.{1}.{2}", chunkName, fileEnumeration & CStr(chunkIndex), chunkExt)
  714.  
  715.                     ' Reset written byte-length counter.
  716.                     sizeWritten = 0L
  717.  
  718.                     ' Create the chunk file to Write the bytes.
  719.                     Using outputStream As New FileStream(chunkFilename, FileMode.Create)
  720.  
  721.                         ' Calculate the amount of buffer-writting operations.
  722.                         writeCounts = CInt(Math.Ceiling(chunkSize / bufferLength))
  723.                         writeCount = 0
  724.  
  725.                         ' Read until reached the end-bytes of the input file.
  726.                         While (inputStream.Position < inputStream.Length) AndAlso (sizeWritten < chunkSize)
  727.  
  728.                             ' Increment the buffer-writting counter.
  729.                             writeCount += 1
  730.  
  731.                             ' If buffer-writting operation is the last buffer-writting operation then...
  732.                             If (writeCount = writeCounts) Then
  733.                                 ' Fix buffer size for writting the last buffer-data.
  734.                                 bufferLength = CInt(chunkSize - sizeWritten)
  735.                             End If
  736.  
  737.                             ' Read bytes from the input file).
  738.                             buffer = binaryReader.ReadBytes(bufferLength)
  739.  
  740.                             ' Write those bytes in the chunk file.
  741.                             outputStream.Write(buffer, 0, buffer.Length)
  742.  
  743.                             ' Increment the bytes-written counter.
  744.                             sizeWritten += buffer.Length
  745.  
  746.                             ' Decrease the bytes-remaining counter.
  747.                             sizeRemaining -= buffer.Length
  748.  
  749.                             ' Set the total progress.
  750.                             totalProgress = (totalSize - sizeRemaining) * (100I / totalSize)
  751.  
  752.                             ' Set the current chunk progress.
  753.                             chunkProgress =
  754.                                 If(Not chunkIndex = chunkCount,
  755.                                    (100I / chunkSize) * (sizeWritten - bufferLength),
  756.                                    (100I / (inputStream.Length - (chunkSize * (chunkIndex - 1)))) * (sizeWritten - bufferLength))
  757.  
  758.                             ' Set the progress event data.
  759.                             progressArguments =
  760.                                 New SplitProgressChangedArgs(
  761.                                     TotalProgress:=If(Not totalProgress > 99.9R, totalProgress, 99.9R),
  762.                                     ChunkProgress:=chunkProgress,
  763.                                     ChunksToCreate:=chunkCount,
  764.                                     ChunksCreated:=chunkIndex - 1L)
  765.  
  766.                             ' Trigger the progress event.
  767.                             RaiseEvent SplitProgressChanged(Me, progressArguments)
  768.  
  769.                         End While ' (inputStream.Position < inputStream.Length) AndAlso (sizeWritten < chunkSize)
  770.  
  771.                         outputStream.Flush()
  772.  
  773.                     End Using ' outputStream
  774.  
  775.                 End While ' (inputStream.Position < inputStream.Length)
  776.  
  777.             End Using ' binaryReader
  778.  
  779.         End Using ' inputStream
  780.  
  781.         ' Set the ending progress event data.
  782.         progressArguments =
  783.             New SplitProgressChangedArgs(
  784.                 TotalProgress:=100.0R,
  785.                 ChunkProgress:=100.0R,
  786.                 ChunksToCreate:=chunkCount,
  787.                 ChunksCreated:=chunkIndex - 1L)
  788.  
  789.         ' Trigger the last progress event.
  790.         RaiseEvent SplitProgressChanged(Me, progressArguments)
  791.  
  792.     End Sub
  793.  
  794.     ''' <summary>
  795.     ''' Merges the chunks of a previously splitted file.
  796.     ''' </summary>
  797.     ''' <param name="sourceChunk">The initial chunk of a splitted file. (eg: 'C:\File.Part.01.avi')</param>
  798.     ''' <param name="targetFile">The target filepath.</param>
  799.     ''' <param name="overwrite">
  800.     ''' If set to <c>true</c>, in case that the specified file in <paramref name="targetFile"/> exists it will be overwritten,
  801.     ''' otherwise, an exception will be thrown.
  802.     ''' </param>
  803.     ''' <param name="deleteChunksAfterMerged">If set to <c>true</c>, the chunks will be deleted after a successful merge operation.</param>
  804.     ''' <exception cref="System.IO.FileNotFoundException">The specified chunk file doesn't exists.</exception>
  805.     ''' <exception cref="System.IO.FileNotFoundException">Only one chunk file found, the last chunk file is missing.</exception>
  806.     ''' <exception cref="System.IO.IOException">The specified target file already exists.</exception>
  807.     ''' <exception cref="System.OverflowException">"Unexpected chunk filesize-count detected, maybe one of the chunk files is corrupt?.".</exception>
  808.     Public Sub Merge(ByVal sourceChunk As String,
  809.                      Optional ByVal targetFile As String = Nothing,
  810.                      Optional ByVal overwrite As Boolean = False,
  811.                      Optional deleteChunksAfterMerged As Boolean = False)
  812.  
  813.         If Not File.Exists(sourceChunk) Then
  814.             Throw New FileNotFoundException("The specified chunk file doesn't exists.", sourceChunk)
  815.             Exit Sub
  816.  
  817.         ElseIf Not overwrite AndAlso File.Exists(targetFile) Then
  818.             Throw New IOException(String.Format("The specified target file already exists: {0}", targetFile))
  819.             Exit Sub
  820.  
  821.         End If
  822.  
  823.         ' The progress event arguments.
  824.         Dim progressArguments As MergeProgressChangedArgs
  825.  
  826.         ' FileInfo instance of the source chunk file.
  827.         Dim fInfo As New FileInfo(sourceChunk)
  828.  
  829.         ' Get the source chunk filename without extension.
  830.         Dim filename As String = Path.GetFileNameWithoutExtension(fInfo.FullName)
  831.         ' Remove the chunk enumeration from the filename.
  832.         filename = filename.Substring(0, filename.LastIndexOf("."c))
  833.  
  834.         ' Set the enumeration pattern to find the chunk files to merge.
  835.         Dim chunkPatternSearch As String =
  836.             filename & ".*" & If(Not String.IsNullOrEmpty(fInfo.Extension), fInfo.Extension, "")
  837.  
  838.         ' Retrieve all the chunk files to merge.
  839.         Dim chunks As IEnumerable(Of FileInfo) =
  840.            From chunk As String In Directory.EnumerateFiles(fInfo.DirectoryName, chunkPatternSearch, SearchOption.TopDirectoryOnly)
  841.            Select New FileInfo(chunk)
  842.  
  843.         If chunks.LongCount < 2L Then ' If chunk files are less than two then...
  844.             Throw New FileNotFoundException("Only one chunk file found, the last chunk file is missing.")
  845.             Exit Sub
  846.         End If
  847.  
  848.         ' The total filesize to merge, in bytes.
  849.         Dim totalSize As Long =
  850.             (From Chunk As FileInfo In chunks Select Chunk.Length).Sum
  851.  
  852.         ' Gets the filesize of the chunk files and the last chunk file, in bytes.
  853.         Dim chunkSizes As Long() =
  854.             (From Chunk As FileInfo In chunks
  855.              Select Chunk.Length Order By Length Descending
  856.             ).Distinct.ToArray
  857.  
  858.         If chunkSizes.LongCount > 2L Then ' If chunk sizes are more than 2...
  859.             Throw New OverflowException("Unexpected chunk filesize-count detected, maybe one of the chunk files is corrupt?.")
  860.             Exit Sub
  861.         End If
  862.  
  863.         ' The remaining size to calculate the percentage, in bytes.
  864.         Dim sizeRemaining As Long = totalSize
  865.  
  866.         ' Counts the length of the current chunk file to calculate the percentage, in bytes.
  867.         Dim sizeWritten As Long
  868.  
  869.         ' Counts the length of the written size on the current chunk file, in bytes.
  870.         Dim chunkSizeWritten As Long
  871.  
  872.         ' The buffer to read data and merge the chunks.
  873.         Dim buffer As Byte()
  874.  
  875.         ' The buffer length.
  876.         Dim bufferLength As Integer = Me.BufferSize
  877.  
  878.         ' The total amount of chunks to merge.
  879.         Dim chunkCount As Long = chunks.LongCount
  880.  
  881.         ' Keeps track of the current chunk.
  882.         Dim chunkIndex As Long
  883.  
  884.         ' Keeps track of the total percentage done.
  885.         Dim totalProgress As Double
  886.  
  887.         ' Create the output file to merge the chunks inside.
  888.         Using outputStream As New FileStream(targetFile, FileMode.Create)
  889.  
  890.             ' Iterate the chunk files.
  891.             For Each chunk As FileInfo In chunks
  892.  
  893.                 ' Open the chunk file to start reading bytes.
  894.                 Using inputStream As New FileStream(chunk.FullName, FileMode.Open)
  895.  
  896.                     Using binaryReader As New BinaryReader(inputStream)
  897.  
  898.                         ' Read until reached the end-bytes of the chunk file.
  899.                         While (inputStream.Position < inputStream.Length)
  900.  
  901.                             ' Read bytes from the chunk file (BufferSize byte-length).
  902.                             buffer = binaryReader.ReadBytes(bufferLength)
  903.  
  904.                             ' Write those bytes in the output file.
  905.                             outputStream.Write(buffer, 0, buffer.Length)
  906.  
  907.                             ' Increment the bytes-written counters.
  908.                             sizeWritten += buffer.Length
  909.                             chunkSizeWritten += buffer.Length
  910.  
  911.                             ' Decrease the bytes-remaining counter.
  912.                             sizeRemaining -= buffer.Length
  913.  
  914.                             ' Set the total progress.
  915.                             totalProgress = (totalSize - sizeRemaining) * (100 / totalSize)
  916.  
  917.                             ' Set the progress event data.
  918.                             progressArguments = New MergeProgressChangedArgs(
  919.                                 TotalProgress:=If(Not totalProgress > 99.9R, totalProgress, 99.9R),
  920.                                 ChunkProgress:=(100 / inputStream.Length) * (chunkSizeWritten - bufferLength),
  921.                                 ChunksToMerge:=chunkCount,
  922.                                 ChunksMerged:=chunkIndex)
  923.  
  924.                             ' Trigger the progress event.
  925.                             RaiseEvent MergeProgressChanged(Me, progressArguments)
  926.  
  927.                         End While ' (inputStream.Position < inputStream.Length)
  928.  
  929.                         chunkIndex += 1I ' Increment the chunk file counter.
  930.                         chunkSizeWritten = 0L ' Reset the bytes-written for the next chunk.
  931.  
  932.                     End Using ' binaryReader
  933.  
  934.                 End Using ' inputStream
  935.  
  936.             Next chunk
  937.  
  938.             outputStream.Flush()
  939.  
  940.         End Using ' outputStream
  941.  
  942.         ' Set the ending progress event data.
  943.         progressArguments = New MergeProgressChangedArgs(
  944.             TotalProgress:=100.0R,
  945.             ChunkProgress:=100.0R,
  946.             ChunksToMerge:=chunkCount,
  947.             ChunksMerged:=chunkIndex - 1L)
  948.  
  949.         ' Trigger the last progress event.
  950.         RaiseEvent MergeProgressChanged(Me, progressArguments)
  951.  
  952.         If deleteChunksAfterMerged Then ' Delethe the chunk files.
  953.  
  954.             For Each chunk As FileInfo In chunks
  955.                 File.Delete(chunk.FullName)
  956.             Next chunk
  957.  
  958.         End If ' deleteChunksAfterMerged
  959.  
  960.     End Sub
  961.  
  962. #End Region
  963.  
  964. #Region " Hidden Methods "
  965.  
  966.     ''' <summary>
  967.     ''' Serves as a hash function for a particular type.
  968.     ''' </summary>
  969.     <EditorBrowsable(EditorBrowsableState.Never)>
  970.     Public Shadows Function GetHashCode() As Integer
  971.         Return MyBase.GetHashCode
  972.     End Function
  973.  
  974.     ''' <summary>
  975.     ''' Gets the System.Type of the current instance.
  976.     ''' </summary>
  977.     ''' <returns>The exact runtime type of the current instance.</returns>
  978.     <EditorBrowsable(EditorBrowsableState.Never)>
  979.     Public Shadows Function [GetType]() As Type
  980.         Return MyBase.GetType
  981.     End Function
  982.  
  983.     ''' <summary>
  984.     ''' Determines whether the specified System.Object instances are considered equal.
  985.     ''' </summary>
  986.     <EditorBrowsable(EditorBrowsableState.Never)>
  987.     Public Shadows Function Equals(ByVal obj As Object) As Boolean
  988.         Return MyBase.Equals(obj)
  989.     End Function
  990.  
  991.     ''' <summary>
  992.     ''' Determines whether the specified System.Object instances are the same instance.
  993.     ''' </summary>
  994.     <EditorBrowsable(EditorBrowsableState.Never)>
  995.     Private Shadows Function ReferenceEquals(ByVal objA As Object, ByVal objB As Object) As Boolean
  996.         Return Nothing
  997.     End Function
  998.  
  999.     ''' <summary>
  1000.     ''' Returns a String that represents the current object.
  1001.     ''' </summary>
  1002.     <EditorBrowsable(EditorBrowsableState.Never)>
  1003.     Public Shadows Function ToString() As String
  1004.         Return MyBase.ToString
  1005.     End Function
  1006.  
  1007. #End Region
  1008.  
  1009. End Class
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement