Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ' ***********************************************************************
- ' Author : Elektro
- ' Last Modified On : 28-May-2015
- ' ***********************************************************************
- ' <copyright file="FileSplitter.vb" company="Elektro Studios">
- ' Copyright (c) Elektro Studios. All rights reserved.
- ' </copyright>
- ' ***********************************************************************
- #Region " Usage Examples "
- 'Public NotInheritable Class Form1
- ' ''' <summary>
- ' ''' Handles the <see cref="FileSplitter"/> instance.
- ' ''' </summary>
- ' Private WithEvents splitter As New FileSplitter() With {.BufferSize = .BufferSize}
- ' ' Splitter settings.
- ' Private ReadOnly workingDir As String = "C:\Test"
- ' Private ReadOnly fileName As String = "File.txt"
- ' Private ReadOnly filePath As String = IO.Path.Combine(workingDir, fileName)
- ' Private ReadOnly chunkName As String = "File.Part"
- ' Private ReadOnly chunkExt As String = "fs"
- ' ' Merger settings.
- ' Private ReadOnly firstChunkPath As String = String.Format("{0}\{1}.01.{2}", workingDir, chunkName, chunkExt)
- ' Private ReadOnly targetFileName As String = String.Format("{0}\{1}.{2}", workingDir, "Merged", IO.Path.GetExtension(fileName))
- ' ' Some default chunk sizes to split a file.
- ' Private ReadOnly kilobyte As Integer = 1024
- ' Private ReadOnly megabyte As Integer = 1048576
- ' Private ReadOnly gigabyte As Integer = 1073741824
- ' Private ReadOnly halfFileSize As Integer = CInt(New IO.FileInfo(filePath).Length / 2)
- ' ' The label controls that will display the progress.
- ' Private labelSplit1, labelSplit2, labelSplit3 As New Label
- ' Private labelMerge1, labelMerge2, labelMerge3 As New Label
- ' ' The button controls to start a split or merge operation.
- ' Private WithEvents buttonSplit, buttonMerge As New Button
- ' ''' <summary>
- ' ''' Initializes a new instance of the <see cref="Form1"/> class.
- ' ''' </summary>
- ' Public Sub New()
- ' ' This call is required by the designer.
- ' Me.InitializeComponent()
- ' ' Set the controls properties.
- ' With buttonSplit
- ' .Text = "Split"
- ' .Font = New Font(Me.Font.FontFamily, 14.0F, FontStyle.Bold)
- ' .Size = New Size(200, 75)
- ' .Location = New Point(0, 0)
- ' .Cursor = Cursors.Hand
- ' End With
- ' With buttonMerge
- ' .Text = "Merge"
- ' .Font = New Font(Me.Font.FontFamily, 14.0F, FontStyle.Bold)
- ' .Size = New Size(200, 75)
- ' .Location = New Point(buttonSplit.Location.X + buttonSplit.Width, 0)
- ' .Cursor = Cursors.Hand
- ' End With
- ' With labelSplit1
- ' .Text = "Total Progress:"
- ' .AutoSize = True
- ' .Font = New Font(Me.Font.FontFamily, 9.0F, FontStyle.Regular)
- ' .Location = New Point(0, buttonSplit.Location.Y + buttonSplit.Height + 10)
- ' End With
- ' With labelSplit2
- ' .Text = "Chunk Progress:"
- ' .AutoSize = True
- ' .Font = New Font(Me.Font.FontFamily, 9.0F, FontStyle.Regular)
- ' .Location = New Point(0, labelSplit1.Location.Y + labelSplit1.Height)
- ' End With
- ' With labelSplit3
- ' .Text = "Chunk Count:"
- ' .AutoSize = True
- ' .Font = New Font(Me.Font.FontFamily, 9.0F, FontStyle.Regular)
- ' .Location = New Point(0, labelSplit2.Location.Y + labelSplit2.Height)
- ' End With
- ' With labelMerge1
- ' .Text = "Total Progress:"
- ' .AutoSize = True
- ' .Font = New Font(Me.Font.FontFamily, 9.0F, FontStyle.Regular)
- ' .Location = New Point(buttonMerge.Location.X, buttonMerge.Location.Y + buttonMerge.Height + 10)
- ' End With
- ' With labelMerge2
- ' .Text = "Chunk Progress:"
- ' .AutoSize = True
- ' .Font = New Font(Me.Font.FontFamily, 9.0F, FontStyle.Regular)
- ' .Location = New Point(buttonMerge.Location.X, labelMerge1.Location.Y + labelMerge1.Height)
- ' End With
- ' With labelMerge3
- ' .Text = "Chunk Count:"
- ' .AutoSize = True
- ' .Font = New Font(Me.Font.FontFamily, 9.0F, FontStyle.Regular)
- ' .Location = New Point(buttonMerge.Location.X, labelMerge2.Location.Y + labelMerge2.Height)
- ' End With
- ' ' Add the controls on the UI.
- 'Me.Controls.AddRange({labelSplit1, labelSplit2, labelSplit3,
- ' labelMerge1, labelMerge2, labelMerge3,
- ' buttonSplit, buttonMerge})
- ' ' Set the Form properties.
- ' With Me
- ' .Size = New Size(buttonSplit.Width + buttonMerge.Width + 20, 200)
- ' .FormBorderStyle = Windows.Forms.FormBorderStyle.FixedDialog
- ' .MaximizeBox = False
- ' End With
- ' End Sub
- ' ''' <summary>
- ' ''' Handles the <see cref="Button.Click"/> event of the <see cref="ButtonSplit"/> control.
- ' ''' </summary>
- ' Private Sub ButtonSplit_Click() Handles buttonSplit.Click
- ' Me.splitter.Split(sourceFile:=Me.filePath,
- ' chunkSize:=Me.halfFileSize,
- ' chunkName:=Me.chunkName,
- ' chunkExt:=Me.chunkExt,
- ' overwrite:=True,
- ' deleteAfterSplit:=False)
- ' ' Or...
- ' 'Me.splitter.Split(sourceFile:=Me.filePath,
- ' ' chunkCount:=2,
- ' ' chunkName:=Me.chunkName,
- ' ' chunkExt:=Me.chunkExt,
- ' ' overwrite:=True,
- ' ' deleteAfterSplit:=False)
- ' End Sub
- ' ''' <summary>
- ' ''' Handles the <see cref="Button.Click"/> event of the <see cref="ButtonMerge"/> control.
- ' ''' </summary>
- ' Private Sub ButtonMerge_Click() Handles buttonMerge.Click
- ' Me.splitter.Merge(sourceChunk:=Me.firstChunkPath,
- ' targetFile:=Me.targetFileName,
- ' overwrite:=True,
- ' deleteChunksAfterMerged:=False)
- ' End Sub
- ' ''' <summary>
- ' ''' Handles the <see cref="FileSplitter.SplitProgressChangedArgs"/> event of the <see cref="Splitter"/> instance.
- ' ''' </summary>
- ' ''' <param name="sender">The source of the event.</param>
- ' ''' <param name="e">The <see cref="FileSplitter.SplitProgressChangedArgs"/> instance containing the event data.</param>
- ' Private Sub Splitter_SplitProgressChangedArgs(ByVal sender As Object, ByVal e As FileSplitter.SplitProgressChangedArgs) _
- ' Handles splitter.SplitProgressChanged
- ' labelSplit1.Text = String.Format("Total Progress: {0}%", e.TotalProgress.ToString("n1"))
- ' labelSplit2.Text = String.Format("Chunk Progress: {0}%", e.ChunkProgress.ToString("n1"))
- ' labelSplit3.Text = String.Format("Current Chunk: {0} of {1}", CStr(e.ChunksCreated + 1), CStr(e.ChunksToCreate))
- ' Application.DoEvents()
- ' End Sub
- ' ''' <summary>
- ' ''' Handles the <see cref="FileSplitter.MergeProgressChangedArgs"/> event of the <see cref="Splitter"/> instance.
- ' ''' </summary>
- ' ''' <param name="sender">The source of the event.</param>
- ' ''' <param name="e">The <see cref="FileSplitter.MergeProgressChangedArgs"/> instance containing the event data.</param>
- ' Private Sub Splitter_MergeProgressChangedArgs(ByVal sender As Object, ByVal e As FileSplitter.MergeProgressChangedArgs) _
- ' Handles splitter.MergeProgressChanged
- ' labelMerge1.Text = String.Format("Total Progress: {0}%", e.TotalProgress.ToString("n1"))
- ' labelMerge2.Text = String.Format("Chunk Progress: {0}%", e.ChunkProgress.ToString("n1"))
- ' labelMerge3.Text = String.Format("Current Chunk: {0} of {1}", CStr(e.ChunksMerged + 1), CStr(e.ChunksToMerge))
- ' Application.DoEvents()
- ' End Sub
- 'End Class
- #End Region
- #Region " Option Statements "
- Option Strict On
- Option Explicit On
- Option Infer Off
- #End Region
- #Region " Imports "
- Imports System.ComponentModel
- Imports System.IO
- #End Region
- ''' <summary>
- ''' Splits a file into manageable chunks, or merge the splitted chunks.
- ''' With progress-percent features.
- ''' </summary>
- Public NotInheritable Class FileSplitter
- #Region " Properties "
- ''' <summary>
- ''' Gets or sets the buffer-size used to split or merge, in Bytes.
- ''' Default value is: 524288 bytes (512 Kb).
- ''' </summary>
- ''' <value>The buffer-size.</value>
- Public Property BufferSize As Integer = 524288
- ' 4096 Bytes ( 4 Kb) This is the default Microsoft's FileStream implementation buffer size.
- ' 8192 Bytes ( 8 Kb)
- ' 16384 Bytes ( 16 Kb)
- ' 32768 Bytes ( 32 Kb)
- ' 65536 Bytes ( 64 Kb)
- ' 131072 Bytes (128 Kb)
- ' 262144 Bytes (256 Kb)
- ' 524288 Bytes (512 Kb)
- ' 1048576 Bytes ( 1 Mb)
- #End Region
- #Region " Events "
- #Region " Event Declarations "
- ''' <summary>
- ''' Occurs when the progress changes when splitting a file.
- ''' </summary>
- Public Event SplitProgressChanged As EventHandler(Of SplitProgressChangedArgs)
- ''' <summary>
- ''' Occurs when the progress changes when merging a file.
- ''' </summary>
- Public Event MergeProgressChanged As EventHandler(Of MergeProgressChangedArgs)
- #End Region
- #Region " Event Data "
- #Region " SplitProgressChanged "
- ''' <summary>
- ''' Contains the event data of the <see cref="FileSplitter.SplitProgressChanged"/> event.
- ''' </summary>
- Public NotInheritable Class SplitProgressChangedArgs : Inherits EventArgs
- #Region " Properties "
- ''' <summary>
- ''' Gets the total progress value.
- ''' (From 0 to 100)
- ''' </summary>
- ''' <value>The total progress value.</value>
- Public ReadOnly Property TotalProgress As Double
- Get
- Return Me.totalProgress1
- End Get
- End Property
- ''' <summary>
- ''' The total progress value.
- ''' (From 0 to 100)
- ''' </summary>
- Private ReadOnly totalProgress1 As Double = 0.0R
- ''' <summary>
- ''' Gets the current chunk progress value.
- ''' (From 0 to 100)
- ''' </summary>
- ''' <value>The current chunk progress value.</value>
- Public ReadOnly Property ChunkProgress As Double
- Get
- Return Me.chunkProgress1
- End Get
- End Property
- ''' <summary>
- ''' The current chunk progress value.
- ''' (From 0 to 100)
- ''' </summary>
- Private ReadOnly chunkProgress1 As Double = 0.0R
- ''' <summary>
- ''' Gets the amount of chunks to create.
- ''' </summary>
- ''' <value>The amount of chunks to create.</value>
- Public ReadOnly Property ChunksToCreate As Long
- Get
- Return Me.chunksToCreate1
- End Get
- End Property
- ''' <summary>
- ''' The amount of chunks to create.
- ''' </summary>
- Private ReadOnly chunksToCreate1 As Long = 0L
- ''' <summary>
- ''' Gets the amount of created chunks.
- ''' </summary>
- ''' <value>The amount of created chunks.</value>
- Public ReadOnly Property ChunksCreated As Long
- Get
- Return Me.chunksCreated1
- End Get
- End Property
- ''' <summary>
- ''' The amount of created chunks.
- ''' </summary>
- Private ReadOnly chunksCreated1 As Long = 0L
- #End Region
- #Region " Constructors "
- ''' <summary>
- ''' Prevents a default instance of the <see cref="FileSplitter.SplitProgressChangedArgs"/> class from being created.
- ''' </summary>
- Private Sub New()
- End Sub
- ''' <summary>
- ''' Initializes a new instance of the <see cref="FileSplitter.SplitProgressChangedArgs"/> class.
- ''' </summary>
- ''' <param name="totalProgress">The total progress value.</param>
- ''' <param name="chunkProgress">The current chunk progress value.</param>
- ''' <param name="chunksToCreate">The amount of chunks to create.</param>
- ''' <param name="chunksCreated">The amount of created chunks.</param>
- Public Sub New(ByVal totalProgress As Double,
- ByVal chunkProgress As Double,
- ByVal chunksToCreate As Long,
- ByVal chunksCreated As Long)
- Me.totalProgress1 = totalProgress
- Me.chunkProgress1 = chunkProgress
- Me.chunksToCreate1 = chunksToCreate
- Me.chunksCreated1 = chunksCreated
- End Sub
- #End Region
- #Region " Hidden Methods "
- ''' <summary>
- ''' Serves as a hash function for a particular type.
- ''' </summary>
- <EditorBrowsable(EditorBrowsableState.Never)>
- Public Shadows Function GetHashCode() As Integer
- Return MyBase.GetHashCode
- End Function
- ''' <summary>
- ''' Gets the System.Type of the current instance.
- ''' </summary>
- ''' <returns>The exact runtime type of the current instance.</returns>
- <EditorBrowsable(EditorBrowsableState.Never)>
- Public Shadows Function [GetType]() As Type
- Return MyBase.GetType
- End Function
- ''' <summary>
- ''' Determines whether the specified System.Object instances are considered equal.
- ''' </summary>
- <EditorBrowsable(EditorBrowsableState.Never)>
- Public Shadows Function Equals(ByVal obj As Object) As Boolean
- Return MyBase.Equals(obj)
- End Function
- ''' <summary>
- ''' Determines whether the specified System.Object instances are the same instance.
- ''' </summary>
- <EditorBrowsable(EditorBrowsableState.Never)>
- Private Shadows Function ReferenceEquals(ByVal objA As Object, ByVal objB As Object) As Boolean
- Return Nothing
- End Function
- ''' <summary>
- ''' Returns a String that represents the current object.
- ''' </summary>
- <EditorBrowsable(EditorBrowsableState.Never)>
- Public Shadows Function ToString() As String
- Return MyBase.ToString
- End Function
- #End Region
- End Class
- #End Region
- #Region " MergeProgressChangedArgs "
- ''' <summary>
- ''' Contains the event data of the <see cref="FileSplitter.MergeProgressChanged"/> event.
- ''' </summary>
- Public NotInheritable Class MergeProgressChangedArgs : Inherits EventArgs
- #Region " Properties "
- ''' <summary>
- ''' Gets the total progress value.
- ''' (From 0 to 100)
- ''' </summary>
- ''' <value>The total progress value.</value>
- Public ReadOnly Property TotalProgress As Double
- Get
- Return Me.totalProgress1
- End Get
- End Property
- ''' <summary>
- ''' The total progress value.
- ''' (From 0 to 100)
- ''' </summary>
- Private ReadOnly totalProgress1 As Double = 0.0R
- ''' <summary>
- ''' Gets the current chunk progress value.
- ''' (From 0 to 100)
- ''' </summary>
- ''' <value>The current chunk progress value.</value>
- Public ReadOnly Property ChunkProgress As Double
- Get
- Return Me.chunkProgress1
- End Get
- End Property
- ''' <summary>
- ''' The current chunk progress value.
- ''' (From 0 to 100)
- ''' </summary>
- Private ReadOnly chunkProgress1 As Double = 0.0R
- ''' <summary>
- ''' Gets the amount of chunks to merge.
- ''' </summary>
- ''' <value>The amount of chunks to merge.</value>
- Public ReadOnly Property ChunksToMerge As Long
- Get
- Return Me.chunksToMerge1
- End Get
- End Property
- ''' <summary>
- ''' The amount of chunks to merge.
- ''' </summary>
- Private ReadOnly chunksToMerge1 As Long = 0L
- ''' <summary>
- ''' Gets the amount of merged chunks.
- ''' </summary>
- ''' <value>The amount of merged chunks.</value>
- Public ReadOnly Property ChunksMerged As Long
- Get
- Return Me.chunksMerged1
- End Get
- End Property
- ''' <summary>
- ''' The amount of merged chunks.
- ''' </summary>
- Private ReadOnly chunksMerged1 As Long = 0L
- #End Region
- #Region " Constructors "
- ''' <summary>
- ''' Prevents a default instance of the <see cref="FileSplitter.MergeProgressChangedArgs"/> class from being created.
- ''' </summary>
- Private Sub New()
- End Sub
- ''' <summary>
- ''' Initializes a new instance of the <see cref="FileSplitter.MergeProgressChangedArgs"/> class.
- ''' </summary>
- ''' <param name="totalProgress">The total progress value.</param>
- ''' <param name="chunkProgress">The current chunk progress value.</param>
- ''' <param name="chunksToMerge">The amount of chunks to merge.</param>
- ''' <param name="chunksMerged">The amount of merged chunks.</param>
- Public Sub New(ByVal totalProgress As Double,
- ByVal chunkProgress As Double,
- ByVal chunksToMerge As Long,
- ByVal chunksMerged As Long)
- Me.totalProgress1 = totalProgress
- Me.chunkProgress1 = chunkProgress
- Me.chunksToMerge1 = chunksToMerge
- Me.chunksMerged1 = chunksMerged
- End Sub
- #End Region
- #Region " Hidden Methods "
- ''' <summary>
- ''' Serves as a hash function for a particular type.
- ''' </summary>
- <EditorBrowsable(EditorBrowsableState.Never)>
- Public Shadows Function GetHashCode() As Integer
- Return MyBase.GetHashCode
- End Function
- ''' <summary>
- ''' Gets the System.Type of the current instance.
- ''' </summary>
- ''' <returns>The exact runtime type of the current instance.</returns>
- <EditorBrowsable(EditorBrowsableState.Never)>
- Public Shadows Function [GetType]() As Type
- Return MyBase.GetType
- End Function
- ''' <summary>
- ''' Determines whether the specified System.Object instances are considered equal.
- ''' </summary>
- <EditorBrowsable(EditorBrowsableState.Never)>
- Public Shadows Function Equals(ByVal obj As Object) As Boolean
- Return MyBase.Equals(obj)
- End Function
- ''' <summary>
- ''' Determines whether the specified System.Object instances are the same instance.
- ''' </summary>
- <EditorBrowsable(EditorBrowsableState.Never)>
- Private Shadows Function ReferenceEquals(ByVal objA As Object, ByVal objB As Object) As Boolean
- Return Nothing
- End Function
- ''' <summary>
- ''' Returns a String that represents the current object.
- ''' </summary>
- <EditorBrowsable(EditorBrowsableState.Never)>
- Public Shadows Function ToString() As String
- Return MyBase.ToString
- End Function
- #End Region
- End Class
- #End Region
- #End Region
- #End Region
- #Region " Public Methods "
- ''' <summary>
- ''' Splits a file into manageable chunks.
- ''' </summary>
- ''' <param name="sourceFile">The file to split.</param>
- ''' <param name="chunkCount">The amount of chunks.</param>
- ''' <param name="chunkName">The name formatting for chunks.</param>
- ''' <param name="chunkExt">The file-extension for chunks.</param>
- ''' <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>
- ''' <param name="deleteAfterSplit">If set to <c>True</c>, the input file will be deleted after a successful split operation.</param>
- ''' <exception cref="System.Exception"></exception>
- Public Sub Split(ByVal sourceFile As String,
- ByVal chunkCount As Integer,
- Optional ByVal chunkName As String = Nothing,
- Optional ByVal chunkExt As String = Nothing,
- Optional ByVal overwrite As Boolean = False,
- Optional ByVal deleteAfterSplit As Boolean = False)
- Dim chunkSize As Long
- Try
- chunkSize = CLng(Math.Ceiling(New FileInfo(sourceFile).Length / chunkCount))
- Catch ex As Exception
- Throw
- End Try
- Me.Split(sourceFile:=sourceFile,
- chunkSize:=chunkSize,
- chunkName:=chunkName,
- chunkExt:=chunkExt,
- overwrite:=overwrite,
- deleteAfterSplit:=deleteAfterSplit)
- End Sub
- ''' <summary>
- ''' Splits a file into manageable chunks.
- ''' </summary>
- ''' <param name="sourceFile">The file to split.</param>
- ''' <param name="chunkSize">The size per chunk.</param>
- ''' <param name="chunkName">The name formatting for chunks.</param>
- ''' <param name="chunkExt">The file-extension for chunks.</param>
- ''' <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>
- ''' <param name="deleteAfterSplit">If set to <c>True</c>, the input file will be deleted after a successful split operation.</param>
- ''' <exception cref="System.IO.FileNotFoundException">The specified source file doesn't exists.</exception>
- ''' <exception cref="System.IO.IOException">File already exists.</exception>
- ''' <exception cref="System.OverflowException">'chunkSize' value should be smaller than the source filesize.</exception>
- Public Sub Split(ByVal sourceFile As String,
- ByVal chunkSize As Long,
- Optional ByVal chunkName As String = Nothing,
- Optional ByVal chunkExt As String = Nothing,
- Optional ByVal overwrite As Boolean = False,
- Optional ByVal deleteAfterSplit As Boolean = False)
- If Not File.Exists(sourceFile) Then
- Throw New FileNotFoundException("The specified source file doesn't exists.", sourceFile)
- Exit Sub
- End If
- ' The progress event arguments.
- Dim progressArguments As SplitProgressChangedArgs
- ' FileInfo instance of the source file.
- Dim fInfo As New FileInfo(sourceFile)
- ' The total filesize to split, in bytes.
- Dim totalSize As Long = fInfo.Length
- ' The remaining size to calculate the percentage, in bytes.
- Dim sizeRemaining As Long = totalSize
- ' Counts the length of the current chunk file to calculate the percentage, in bytes.
- Dim sizeWritten As Long
- ' The buffer to read data and write the chunks.
- Dim buffer As Byte()
- ' The buffer length.
- Dim bufferLength As Integer
- ' The total amount of chunks to create.
- Dim chunkCount As Long = CLng(Math.Ceiling((fInfo.Length) / (chunkSize)))
- ' Keeps track of the current chunk.
- Dim chunkIndex As Long
- ' Keeps track of the amount of buffer-writting operations.
- Dim writeCounts As Integer
- ' Keeps track of the current buffer-writting operation.
- Dim writeCount As Integer
- ' Keeps track of the total percentage done.
- Dim totalProgress As Double
- ' Keeps track of the current chunk percentage done.
- Dim chunkProgress As Double
- ' A zero-filled string to enumerate the chunk parts.
- Dim fileEnumeration As String
- ' The chunks filename.
- Dim chunkFilename As String
- ' The chunks basename.
- chunkName = If(String.IsNullOrEmpty(chunkName),
- Path.Combine(fInfo.DirectoryName, Path.GetFileNameWithoutExtension(fInfo.Name)),
- Path.Combine(fInfo.DirectoryName, chunkName))
- ' The chunks file extension.
- chunkExt = If(String.IsNullOrEmpty(chunkExt),
- fInfo.Extension.Substring(1),
- chunkExt)
- Select Case chunkSize ' Set buffer size and calculate chunk count.
- Case Is >= fInfo.Length ' chunk size is bigger than source-file size.
- Throw New OverflowException("'chunkSize' value should be smaller than the source filesize.")
- Exit Sub
- Case Is < Me.BufferSize ' chunk size is smaller than buffer size.
- bufferLength = CInt(chunkSize)
- Case Else ' chunk size is bigger than buffer size.
- bufferLength = Me.BufferSize
- End Select ' chunkSize
- If Not overwrite Then ' If not file overwriting is allowed then...
- For index As Long = 1L To chunkCount ' Start index based on 1 (eg. "File.Part.1.ext").
- ' Set chunk filename.
- fileEnumeration = New String("0"c, CStr(chunkCount).Length - CStr(index).Length)
- chunkFilename = String.Format("{0}.{1}.{2}", chunkName, fileEnumeration & CStr(index), chunkExt)
- ' If chunk file already exists then...
- If File.Exists(chunkFilename) Then
- Throw New IOException(String.Format("File already exists: {0}", chunkFilename))
- Exit Sub
- End If
- Next index
- End If ' overwrite
- ' Open the file to start reading bytes.
- Using inputStream As New FileStream(fInfo.FullName, FileMode.Open)
- Using binaryReader As New BinaryReader(inputStream)
- While (inputStream.Position < inputStream.Length)
- ' Increment the chunk file counter.
- chunkIndex += 1L
- ' Set chunk filename.
- fileEnumeration = New String("0"c, CStr(chunkCount).Length - CStr(chunkIndex).Length)
- chunkFilename = String.Format("{0}.{1}.{2}", chunkName, fileEnumeration & CStr(chunkIndex), chunkExt)
- ' Reset written byte-length counter.
- sizeWritten = 0L
- ' Create the chunk file to Write the bytes.
- Using outputStream As New FileStream(chunkFilename, FileMode.Create)
- ' Calculate the amount of buffer-writting operations.
- writeCounts = CInt(Math.Ceiling(chunkSize / bufferLength))
- writeCount = 0
- ' Read until reached the end-bytes of the input file.
- While (inputStream.Position < inputStream.Length) AndAlso (sizeWritten < chunkSize)
- ' Increment the buffer-writting counter.
- writeCount += 1
- ' If buffer-writting operation is the last buffer-writting operation then...
- If (writeCount = writeCounts) Then
- ' Fix buffer size for writting the last buffer-data.
- bufferLength = CInt(chunkSize - sizeWritten)
- End If
- ' Read bytes from the input file).
- buffer = binaryReader.ReadBytes(bufferLength)
- ' Write those bytes in the chunk file.
- outputStream.Write(buffer, 0, buffer.Length)
- ' Increment the bytes-written counter.
- sizeWritten += buffer.Length
- ' Decrease the bytes-remaining counter.
- sizeRemaining -= buffer.Length
- ' Set the total progress.
- totalProgress = (totalSize - sizeRemaining) * (100I / totalSize)
- ' Set the current chunk progress.
- chunkProgress =
- If(Not chunkIndex = chunkCount,
- (100I / chunkSize) * (sizeWritten - bufferLength),
- (100I / (inputStream.Length - (chunkSize * (chunkIndex - 1)))) * (sizeWritten - bufferLength))
- ' Set the progress event data.
- progressArguments =
- New SplitProgressChangedArgs(
- TotalProgress:=If(Not totalProgress > 99.9R, totalProgress, 99.9R),
- ChunkProgress:=chunkProgress,
- ChunksToCreate:=chunkCount,
- ChunksCreated:=chunkIndex - 1L)
- ' Trigger the progress event.
- RaiseEvent SplitProgressChanged(Me, progressArguments)
- End While ' (inputStream.Position < inputStream.Length) AndAlso (sizeWritten < chunkSize)
- outputStream.Flush()
- End Using ' outputStream
- End While ' (inputStream.Position < inputStream.Length)
- End Using ' binaryReader
- End Using ' inputStream
- ' Set the ending progress event data.
- progressArguments =
- New SplitProgressChangedArgs(
- TotalProgress:=100.0R,
- ChunkProgress:=100.0R,
- ChunksToCreate:=chunkCount,
- ChunksCreated:=chunkIndex - 1L)
- ' Trigger the last progress event.
- RaiseEvent SplitProgressChanged(Me, progressArguments)
- End Sub
- ''' <summary>
- ''' Merges the chunks of a previously splitted file.
- ''' </summary>
- ''' <param name="sourceChunk">The initial chunk of a splitted file. (eg: 'C:\File.Part.01.avi')</param>
- ''' <param name="targetFile">The target filepath.</param>
- ''' <param name="overwrite">
- ''' If set to <c>true</c>, in case that the specified file in <paramref name="targetFile"/> exists it will be overwritten,
- ''' otherwise, an exception will be thrown.
- ''' </param>
- ''' <param name="deleteChunksAfterMerged">If set to <c>true</c>, the chunks will be deleted after a successful merge operation.</param>
- ''' <exception cref="System.IO.FileNotFoundException">The specified chunk file doesn't exists.</exception>
- ''' <exception cref="System.IO.FileNotFoundException">Only one chunk file found, the last chunk file is missing.</exception>
- ''' <exception cref="System.IO.IOException">The specified target file already exists.</exception>
- ''' <exception cref="System.OverflowException">"Unexpected chunk filesize-count detected, maybe one of the chunk files is corrupt?.".</exception>
- Public Sub Merge(ByVal sourceChunk As String,
- Optional ByVal targetFile As String = Nothing,
- Optional ByVal overwrite As Boolean = False,
- Optional deleteChunksAfterMerged As Boolean = False)
- If Not File.Exists(sourceChunk) Then
- Throw New FileNotFoundException("The specified chunk file doesn't exists.", sourceChunk)
- Exit Sub
- ElseIf Not overwrite AndAlso File.Exists(targetFile) Then
- Throw New IOException(String.Format("The specified target file already exists: {0}", targetFile))
- Exit Sub
- End If
- ' The progress event arguments.
- Dim progressArguments As MergeProgressChangedArgs
- ' FileInfo instance of the source chunk file.
- Dim fInfo As New FileInfo(sourceChunk)
- ' Get the source chunk filename without extension.
- Dim filename As String = Path.GetFileNameWithoutExtension(fInfo.FullName)
- ' Remove the chunk enumeration from the filename.
- filename = filename.Substring(0, filename.LastIndexOf("."c))
- ' Set the enumeration pattern to find the chunk files to merge.
- Dim chunkPatternSearch As String =
- filename & ".*" & If(Not String.IsNullOrEmpty(fInfo.Extension), fInfo.Extension, "")
- ' Retrieve all the chunk files to merge.
- Dim chunks As IEnumerable(Of FileInfo) =
- From chunk As String In Directory.EnumerateFiles(fInfo.DirectoryName, chunkPatternSearch, SearchOption.TopDirectoryOnly)
- Select New FileInfo(chunk)
- If chunks.LongCount < 2L Then ' If chunk files are less than two then...
- Throw New FileNotFoundException("Only one chunk file found, the last chunk file is missing.")
- Exit Sub
- End If
- ' The total filesize to merge, in bytes.
- Dim totalSize As Long =
- (From Chunk As FileInfo In chunks Select Chunk.Length).Sum
- ' Gets the filesize of the chunk files and the last chunk file, in bytes.
- Dim chunkSizes As Long() =
- (From Chunk As FileInfo In chunks
- Select Chunk.Length Order By Length Descending
- ).Distinct.ToArray
- If chunkSizes.LongCount > 2L Then ' If chunk sizes are more than 2...
- Throw New OverflowException("Unexpected chunk filesize-count detected, maybe one of the chunk files is corrupt?.")
- Exit Sub
- End If
- ' The remaining size to calculate the percentage, in bytes.
- Dim sizeRemaining As Long = totalSize
- ' Counts the length of the current chunk file to calculate the percentage, in bytes.
- Dim sizeWritten As Long
- ' Counts the length of the written size on the current chunk file, in bytes.
- Dim chunkSizeWritten As Long
- ' The buffer to read data and merge the chunks.
- Dim buffer As Byte()
- ' The buffer length.
- Dim bufferLength As Integer = Me.BufferSize
- ' The total amount of chunks to merge.
- Dim chunkCount As Long = chunks.LongCount
- ' Keeps track of the current chunk.
- Dim chunkIndex As Long
- ' Keeps track of the total percentage done.
- Dim totalProgress As Double
- ' Create the output file to merge the chunks inside.
- Using outputStream As New FileStream(targetFile, FileMode.Create)
- ' Iterate the chunk files.
- For Each chunk As FileInfo In chunks
- ' Open the chunk file to start reading bytes.
- Using inputStream As New FileStream(chunk.FullName, FileMode.Open)
- Using binaryReader As New BinaryReader(inputStream)
- ' Read until reached the end-bytes of the chunk file.
- While (inputStream.Position < inputStream.Length)
- ' Read bytes from the chunk file (BufferSize byte-length).
- buffer = binaryReader.ReadBytes(bufferLength)
- ' Write those bytes in the output file.
- outputStream.Write(buffer, 0, buffer.Length)
- ' Increment the bytes-written counters.
- sizeWritten += buffer.Length
- chunkSizeWritten += buffer.Length
- ' Decrease the bytes-remaining counter.
- sizeRemaining -= buffer.Length
- ' Set the total progress.
- totalProgress = (totalSize - sizeRemaining) * (100 / totalSize)
- ' Set the progress event data.
- progressArguments = New MergeProgressChangedArgs(
- TotalProgress:=If(Not totalProgress > 99.9R, totalProgress, 99.9R),
- ChunkProgress:=(100 / inputStream.Length) * (chunkSizeWritten - bufferLength),
- ChunksToMerge:=chunkCount,
- ChunksMerged:=chunkIndex)
- ' Trigger the progress event.
- RaiseEvent MergeProgressChanged(Me, progressArguments)
- End While ' (inputStream.Position < inputStream.Length)
- chunkIndex += 1I ' Increment the chunk file counter.
- chunkSizeWritten = 0L ' Reset the bytes-written for the next chunk.
- End Using ' binaryReader
- End Using ' inputStream
- Next chunk
- outputStream.Flush()
- End Using ' outputStream
- ' Set the ending progress event data.
- progressArguments = New MergeProgressChangedArgs(
- TotalProgress:=100.0R,
- ChunkProgress:=100.0R,
- ChunksToMerge:=chunkCount,
- ChunksMerged:=chunkIndex - 1L)
- ' Trigger the last progress event.
- RaiseEvent MergeProgressChanged(Me, progressArguments)
- If deleteChunksAfterMerged Then ' Delethe the chunk files.
- For Each chunk As FileInfo In chunks
- File.Delete(chunk.FullName)
- Next chunk
- End If ' deleteChunksAfterMerged
- End Sub
- #End Region
- #Region " Hidden Methods "
- ''' <summary>
- ''' Serves as a hash function for a particular type.
- ''' </summary>
- <EditorBrowsable(EditorBrowsableState.Never)>
- Public Shadows Function GetHashCode() As Integer
- Return MyBase.GetHashCode
- End Function
- ''' <summary>
- ''' Gets the System.Type of the current instance.
- ''' </summary>
- ''' <returns>The exact runtime type of the current instance.</returns>
- <EditorBrowsable(EditorBrowsableState.Never)>
- Public Shadows Function [GetType]() As Type
- Return MyBase.GetType
- End Function
- ''' <summary>
- ''' Determines whether the specified System.Object instances are considered equal.
- ''' </summary>
- <EditorBrowsable(EditorBrowsableState.Never)>
- Public Shadows Function Equals(ByVal obj As Object) As Boolean
- Return MyBase.Equals(obj)
- End Function
- ''' <summary>
- ''' Determines whether the specified System.Object instances are the same instance.
- ''' </summary>
- <EditorBrowsable(EditorBrowsableState.Never)>
- Private Shadows Function ReferenceEquals(ByVal objA As Object, ByVal objB As Object) As Boolean
- Return Nothing
- End Function
- ''' <summary>
- ''' Returns a String that represents the current object.
- ''' </summary>
- <EditorBrowsable(EditorBrowsableState.Never)>
- Public Shadows Function ToString() As String
- Return MyBase.ToString
- End Function
- #End Region
- End Class
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement