Advertisement
Guest User

FileSplitter, C# online translation, by ElektroStudios

a guest
May 27th, 2015
354
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 27.04 KB | None | 0 0
  1. // ***********************************************************************
  2. // Author           : Elektro
  3. // Last Modified On : 28-May-2015
  4. // ***********************************************************************
  5. // <copyright file="FileSplitter.vb" company="Elektro Studios">
  6. //     Copyright (c) Elektro Studios. All rights reserved.
  7. // </copyright>
  8. // ***********************************************************************
  9.  
  10. #region " Usage Examples "
  11.  
  12. // Contenido omitido ...
  13.  
  14. #endregion
  15.  
  16. #region " Usings "
  17.  
  18. using System.ComponentModel;
  19. using System.IO;
  20.  
  21. using Microsoft.VisualBasic;
  22. using System;
  23. using System.Collections;
  24. using System.Collections.Generic;
  25. using System.Data;
  26. using System.Diagnostics;
  27.  
  28. #endregion
  29.  
  30. /// <summary>
  31. /// Splits a file into manageable chunks, or merge the splitted chunks.
  32. /// With progress-percent features.
  33. /// </summary>
  34. public sealed class FileSplitter
  35. {
  36.  
  37.   #region " Properties "
  38.  
  39.   /// <summary>
  40.   /// Gets or sets the buffer-size used to split or merge, in Bytes.
  41.   /// Default value is: 524288 bytes (512 Kb).
  42.   /// </summary>
  43.   /// <value>The buffer-size.</value>
  44.   public int BufferSize { get; set; }
  45.   //    4096 Bytes (  4 Kb) This is the default Microsoft's FileStream implementation buffer size.
  46.   //    8192 Bytes (  8 Kb)
  47.   //   16384 Bytes ( 16 Kb)
  48.   //   32768 Bytes ( 32 Kb)
  49.   //   65536 Bytes ( 64 Kb)
  50.   //  131072 Bytes (128 Kb)
  51.   //  262144 Bytes (256 Kb)
  52.   //  524288 Bytes (512 Kb)
  53.   // 1048576 Bytes (  1 Mb)
  54.  
  55.   #endregion
  56.  
  57.   #region " Events "
  58.  
  59.   #region " Event Declarations "
  60.  
  61.   /// <summary>
  62.   /// Occurs when the progress changes when splitting a file.
  63.   /// </summary>
  64.   public event EventHandler<SplitProgressChangedArgs> SplitProgressChanged;
  65.  
  66.   /// <summary>
  67.   /// Occurs when the progress changes when merging a file.
  68.   /// </summary>
  69.   public event EventHandler<MergeProgressChangedArgs> MergeProgressChanged;
  70.  
  71.   #endregion
  72.  
  73.   #region " Event Data "
  74.  
  75.   #region " SplitProgressChanged "
  76.  
  77.   /// <summary>
  78.   /// Contains the event data of the <see cref="FileSplitter.SplitProgressChanged"/> event.
  79.   /// </summary>
  80.   public sealed class SplitProgressChangedArgs : EventArgs
  81.   {
  82.  
  83.     #region " Properties "
  84.  
  85.     /// <summary>
  86.     /// Gets the total progress value.
  87.     /// (From 0 to 100)
  88.     /// </summary>
  89.     /// <value>The total progress value.</value>
  90.     public double TotalProgress {
  91.       get { return this.totalProgress1; }
  92.     }
  93.  
  94.     /// <summary>
  95.     /// The total progress value.
  96.     /// (From 0 to 100)
  97.     /// </summary>
  98.     private readonly double totalProgress1;
  99.  
  100.     /// <summary>
  101.     /// Gets the current chunk progress value.
  102.     /// (From 0 to 100)
  103.     /// </summary>
  104.     /// <value>The current chunk progress value.</value>
  105.     public double ChunkProgress {
  106.       get { return this.chunkProgress1; }
  107.     }
  108.  
  109.     /// <summary>
  110.     /// The current chunk progress value.
  111.     /// (From 0 to 100)
  112.     /// </summary>
  113.     private readonly double chunkProgress1;
  114.  
  115.     /// <summary>
  116.     /// Gets the amount of chunks to create.
  117.     /// </summary>
  118.     /// <value>The amount of chunks to create.</value>
  119.     public long ChunksToCreate {
  120.       get { return this.chunksToCreate1; }
  121.     }
  122.  
  123.     /// <summary>
  124.     /// The amount of chunks to create.
  125.     /// </summary>
  126.     private readonly long chunksToCreate1;
  127.  
  128.     /// <summary>
  129.     /// Gets the amount of created chunks.
  130.     /// </summary>
  131.     /// <value>The amount of created chunks.</value>
  132.     public long ChunksCreated {
  133.       get { return this.chunksCreated1; }
  134.     }
  135.  
  136.     /// <summary>
  137.     /// The amount of created chunks.
  138.     /// </summary>
  139.     private readonly long chunksCreated1;
  140.     #endregion
  141.  
  142.     #region " Ctors "
  143.  
  144.     /// <summary>
  145.     /// Prevents a default instance of the <see cref="FileSplitter.SplitProgressChangedArgs"/> class from being created.
  146.     /// </summary>
  147.     private SplitProgressChangedArgs()
  148.     {}
  149.  
  150.     /// <summary>
  151.     /// Initializes a new instance of the <see cref="FileSplitter.SplitProgressChangedArgs"/> class.
  152.     /// </summary>
  153.     /// <param name="totalProgress">The total progress value.</param>
  154.     /// <param name="chunkProgress">The current chunk progress value.</param>
  155.     /// <param name="chunksToCreate">The amount of chunks to create.</param>
  156.     /// <param name="chunksCreated">The amount of created chunks.</param>
  157.     public SplitProgressChangedArgs(double totalProgress, double chunkProgress, long chunksToCreate, long chunksCreated)
  158.     {
  159.       this.totalProgress1 = totalProgress;
  160.       this.chunkProgress1 = chunkProgress;
  161.       this.chunksToCreate1 = chunksToCreate;
  162.       this.chunksCreated1 = chunksCreated;
  163.     }
  164.  
  165.     #endregion
  166.  
  167.     #region " Hidden Methods "
  168.  
  169.     /// <summary>
  170.     /// Serves as a hash function for a particular type.
  171.     /// </summary>
  172.     [EditorBrowsable(EditorBrowsableState.Never)]
  173.     public new int GetHashCode()
  174.     {
  175.       return base.GetHashCode;
  176.     }
  177.  
  178.     /// <summary>
  179.     /// Gets the System.Type of the current instance.
  180.     /// </summary>
  181.     /// <returns>The exact runtime type of the current instance.</returns>
  182.     [EditorBrowsable(EditorBrowsableState.Never)]
  183.     public new Type GetType()
  184.     {
  185.       return base.GetType;
  186.     }
  187.  
  188.     /// <summary>
  189.     /// Determines whether the specified System.Object instances are considered equal.
  190.     /// </summary>
  191.     [EditorBrowsable(EditorBrowsableState.Never)]
  192.     public new bool Equals(object obj)
  193.     {
  194.       return base.Equals(obj);
  195.     }
  196.  
  197.     /// <summary>
  198.     /// Determines whether the specified System.Object instances are the same instance.
  199.     /// </summary>
  200.     [EditorBrowsable(EditorBrowsableState.Never)]
  201.     private new bool ReferenceEquals(object objA, object objB)
  202.     {
  203.       return null;
  204.     }
  205.  
  206.     /// <summary>
  207.     /// Returns a String that represents the current object.
  208.     /// </summary>
  209.     [EditorBrowsable(EditorBrowsableState.Never)]
  210.     public new string ToString()
  211.     {
  212.       return base.ToString;
  213.     }
  214.  
  215.     #endregion
  216.  
  217.   }
  218.  
  219.   #endregion
  220.  
  221.   #region " MergeProgressChangedArgs "
  222.  
  223.   /// <summary>
  224.   /// Contains the event data of the <see cref="FileSplitter.MergeProgressChanged"/> event.
  225.   /// </summary>
  226.   public sealed class MergeProgressChangedArgs : EventArgs
  227.   {
  228.  
  229.     #region " Properties "
  230.  
  231.     /// <summary>
  232.     /// Gets the total progress value.
  233.     /// (From 0 to 100)
  234.     /// </summary>
  235.     /// <value>The total progress value.</value>
  236.     public double TotalProgress {
  237.       get { return this.totalProgress1; }
  238.     }
  239.  
  240.     /// <summary>
  241.     /// The total progress value.
  242.     /// (From 0 to 100)
  243.     /// </summary>
  244.     private readonly double totalProgress1;
  245.  
  246.     /// <summary>
  247.     /// Gets the current chunk progress value.
  248.     /// (From 0 to 100)
  249.     /// </summary>
  250.     /// <value>The current chunk progress value.</value>
  251.     public double ChunkProgress {
  252.       get { return this.chunkProgress1; }
  253.     }
  254.  
  255.     /// <summary>
  256.     /// The current chunk progress value.
  257.     /// (From 0 to 100)
  258.     /// </summary>
  259.     private readonly double chunkProgress1;
  260.  
  261.     /// <summary>
  262.     /// Gets the amount of chunks to merge.
  263.     /// </summary>
  264.     /// <value>The amount of chunks to merge.</value>
  265.     public long ChunksToMerge {
  266.       get { return this.chunksToMerge1; }
  267.     }
  268.  
  269.     /// <summary>
  270.     /// The amount of chunks to merge.
  271.     /// </summary>
  272.     private readonly long chunksToMerge1;
  273.  
  274.     /// <summary>
  275.     /// Gets the amount of merged chunks.
  276.     /// </summary>
  277.     /// <value>The amount of merged chunks.</value>
  278.     public long ChunksMerged {
  279.       get { return this.chunksMerged1; }
  280.     }
  281.  
  282.     /// <summary>
  283.     /// The amount of merged chunks.
  284.     /// </summary>
  285.     private readonly long chunksMerged1;
  286.  
  287.     #endregion
  288.  
  289.     #region " Constructors "
  290.  
  291.     /// <summary>
  292.     /// Prevents a default instance of the <see cref="FileSplitter.MergeProgressChangedArgs"/> class from being created.
  293.     /// </summary>
  294.     private MergeProgressChangedArgs()
  295.     {}
  296.  
  297.     /// <summary>
  298.     /// Initializes a new instance of the <see cref="FileSplitter.MergeProgressChangedArgs"/> class.
  299.     /// </summary>
  300.     /// <param name="totalProgress">The total progress value.</param>
  301.     /// <param name="chunkProgress">The current chunk progress value.</param>
  302.     /// <param name="chunksToMerge">The amount of chunks to merge.</param>
  303.     /// <param name="chunksMerged">The amount of merged chunks.</param>
  304.     public MergeProgressChangedArgs(double totalProgress, double chunkProgress, long chunksToMerge, long chunksMerged)
  305.     {
  306.       this.totalProgress1 = totalProgress;
  307.       this.chunkProgress1 = chunkProgress;
  308.       this.chunksToMerge1 = chunksToMerge;
  309.       this.chunksMerged1 = chunksMerged;
  310.     }
  311.  
  312.     #endregion
  313.  
  314.     #region " Hidden Methods "
  315.  
  316.     /// <summary>
  317.     /// Serves as a hash function for a particular type.
  318.     /// </summary>
  319.     [EditorBrowsable(EditorBrowsableState.Never)]
  320.     public new int GetHashCode()
  321.     {
  322.       return base.GetHashCode;
  323.     }
  324.  
  325.     /// <summary>
  326.     /// Gets the System.Type of the current instance.
  327.     /// </summary>
  328.     /// <returns>The exact runtime type of the current instance.</returns>
  329.     [EditorBrowsable(EditorBrowsableState.Never)]
  330.     public new Type GetType()
  331.     {
  332.       return base.GetType;
  333.     }
  334.  
  335.     /// <summary>
  336.     /// Determines whether the specified System.Object instances are considered equal.
  337.     /// </summary>
  338.     [EditorBrowsable(EditorBrowsableState.Never)]
  339.     public new bool Equals(object obj)
  340.     {
  341.       return base.Equals(obj);
  342.     }
  343.  
  344.     /// <summary>
  345.     /// Determines whether the specified System.Object instances are the same instance.
  346.     /// </summary>
  347.     [EditorBrowsable(EditorBrowsableState.Never)]
  348.     private new bool ReferenceEquals(object objA, object objB)
  349.     {
  350.       return null;
  351.     }
  352.  
  353.     /// <summary>
  354.     /// Returns a String that represents the current object.
  355.     /// </summary>
  356.     [EditorBrowsable(EditorBrowsableState.Never)]
  357.     public new string ToString()
  358.     {
  359.       return base.ToString;
  360.     }
  361.  
  362.     #endregion
  363.  
  364.   }
  365.  
  366.   #endregion
  367.  
  368.   #endregion
  369.  
  370.   #endregion
  371.  
  372.   #region " Public Methods "
  373.  
  374.   /// <summary>
  375.   /// Splits a file into manageable chunks.
  376.   /// </summary>
  377.   /// <param name="sourceFile">The file to split.</param>
  378.   /// <param name="chunkCount">The amount of chunks.</param>
  379.   /// <param name="chunkName">The name formatting for chunks.</param>
  380.   /// <param name="chunkExt">The file-extension for chunks.</param>
  381.   /// <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>
  382.   /// <param name="deleteAfterSplit">If set to <c>True</c>, the input file will be deleted after a successful split operation.</param>
  383.   /// <exception cref="System.Exception"></exception>
  384.   public void Split(string sourceFile,
  385.                     int chunkCount,
  386.                     string chunkName = null,
  387.                     string chunkExt = null,
  388.                     bool overwrite = false,
  389.                     bool deleteAfterSplit = false)
  390.  
  391.   {
  392.     long chunkSize = 0;
  393.     try {
  394.       chunkSize = Convert.ToInt64(Math.Ceiling(new FileInfo(sourceFile).Length / chunkCount));
  395.     } catch (Exception ex) {
  396.       throw;
  397.     }
  398.  
  399.     this.Split(sourceFile: sourceFile,
  400.                chunkSize: chunkSize,
  401.                chunkName: chunkName,
  402.                chunkExt: chunkExt,
  403.                overwrite: overwrite,
  404.                deleteAfterSplit: deleteAfterSplit);
  405.   }
  406.  
  407.   /// <summary>
  408.   /// Splits a file into manageable chunks.
  409.   /// </summary>
  410.   /// <param name="sourceFile">The file to split.</param>
  411.   /// <param name="chunkSize">The size per chunk.</param>
  412.   /// <param name="chunkName">The name formatting for chunks.</param>
  413.   /// <param name="chunkExt">The file-extension for chunks.</param>
  414.   /// <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>
  415.   /// <param name="deleteAfterSplit">If set to <c>True</c>, the input file will be deleted after a successful split operation.</param>
  416.   /// <exception cref="System.IO.FileNotFoundException">The specified source file doesn't exists.</exception>
  417.   /// <exception cref="System.IO.IOException">File already exists.</exception>
  418.   /// <exception cref="System.OverflowException">'chunkSize' value should be smaller than the source filesize.</exception>
  419.   public void Split(string sourceFile,
  420.                     long chunkSize,
  421.                     string chunkName = null,
  422.                     string chunkExt = null,
  423.                     bool overwrite = false,
  424.                     bool deleteAfterSplit = false)
  425.  
  426.   {
  427.     if (!File.Exists(sourceFile)) {
  428.       throw new FileNotFoundException("The specified source file doesn't exists.", sourceFile);
  429.       return;
  430.     }
  431.  
  432.     // The progress event arguments.
  433.     SplitProgressChangedArgs progressArguments = null;
  434.  
  435.     // FileInfo instance of the source file.
  436.     FileInfo fInfo = new FileInfo(sourceFile);
  437.  
  438.     // The total filesize to split, in bytes.
  439.     long totalSize = fInfo.Length;
  440.  
  441.     // The remaining size to calculate the percentage, in bytes.
  442.     long sizeRemaining = totalSize;
  443.  
  444.     // Counts the length of the current chunk file to calculate the percentage, in bytes.
  445.     long sizeWritten = 0;
  446.  
  447.     // The buffer to read data and write the chunks.
  448.     byte[] buffer = null;
  449.  
  450.     // The buffer length.
  451.     int bufferLength = 0;
  452.  
  453.     // The total amount of chunks to create.
  454.     long chunkCount = Convert.ToInt64(Math.Ceiling((fInfo.Length) / (chunkSize)));
  455.  
  456.     // Keeps track of the current chunk.
  457.     long chunkIndex = 0;
  458.  
  459.     // Keeps track of the amount of buffer-writting operations.
  460.     int writeCounts = 0;
  461.  
  462.     // Keeps track of the current buffer-writting operation.
  463.     int writeCount = 0;
  464.  
  465.     // Keeps track of the total percentage done.
  466.     double totalProgress = 0;
  467.  
  468.     // Keeps track of the current chunk percentage done.
  469.     double chunkProgress = 0;
  470.  
  471.     // A zero-filled string to enumerate the chunk parts.
  472.     string fileEnumeration = null;
  473.  
  474.     // The chunks filename.
  475.     string chunkFilename = null;
  476.  
  477.     // The chunks basename.
  478.     chunkName = string.IsNullOrEmpty(chunkName) ? Path.Combine(fInfo.DirectoryName, Path.GetFileNameWithoutExtension(fInfo.Name)) : Path.Combine(fInfo.DirectoryName, chunkName);
  479.  
  480.     // The chunks file extension.
  481.     chunkExt = string.IsNullOrEmpty(chunkExt) ? fInfo.Extension.Substring(1) : chunkExt;
  482.  
  483.     // chunk size is bigger than source-file size.
  484.     if (chunkSize >= fInfo.Length) {
  485.       throw new OverflowException("'chunkSize' value should be smaller than the source filesize.");
  486.       return;
  487.  
  488.     // chunk size is smaller than buffer size.
  489.     } else if (chunkSize < this.BufferSize) {
  490.       bufferLength = Convert.ToInt32(chunkSize);
  491.  
  492.     // chunk size is bigger than buffer size.
  493.     } else {
  494.       bufferLength = this.BufferSize;
  495.  
  496.     }
  497.  
  498.     // If not file overwriting is allowed then...
  499.     if (!overwrite) {
  500.  
  501.       // Start index based on 1 (eg. "File.Part.1.ext").
  502.       for (long index = 1L; index <= chunkCount; index++) {
  503.  
  504.         // Set chunk filename.
  505.         fileEnumeration = new string('0', Convert.ToString(chunkCount).Length - Convert.ToString(index).Length);
  506.         chunkFilename = string.Format("{0}.{1}.{2}", chunkName, fileEnumeration + Convert.ToString(index), chunkExt);
  507.  
  508.         // If chunk file already exists then...
  509.         if (File.Exists(chunkFilename)) {
  510.           throw new IOException(string.Format("File already exists: {0}", chunkFilename));
  511.           return;
  512.         }
  513.  
  514.       }
  515.  
  516.     }
  517.     // overwrite
  518.  
  519.     // Open the file to start reading bytes.
  520.     using (FileStream inputStream = new FileStream(fInfo.FullName, FileMode.Open)) {
  521.  
  522.       using (BinaryReader binaryReader = new BinaryReader(inputStream)) {
  523.  
  524.  
  525.         while ((inputStream.Position < inputStream.Length)) {
  526.           // Increment the chunk file counter.
  527.           chunkIndex += 1L;
  528.  
  529.           // Set chunk filename.
  530.           fileEnumeration = new string('0', Convert.ToString(chunkCount).Length - Convert.ToString(chunkIndex).Length);
  531.           chunkFilename = string.Format("{0}.{1}.{2}", chunkName, fileEnumeration + Convert.ToString(chunkIndex), chunkExt);
  532.  
  533.           // Reset written byte-length counter.
  534.           sizeWritten = 0L;
  535.  
  536.           // Create the chunk file to Write the bytes.
  537.           using (FileStream outputStream = new FileStream(chunkFilename, FileMode.Create)) {
  538.  
  539.             // Calculate the amount of buffer-writting operations.
  540.             writeCounts = Convert.ToInt32(Math.Ceiling(chunkSize / bufferLength));
  541.             writeCount = 0;
  542.  
  543.             // Read until reached the end-bytes of the input file.
  544.  
  545.             while ((inputStream.Position < inputStream.Length) && (sizeWritten < chunkSize)) {
  546.               // Increment the buffer-writting counter.
  547.               writeCount += 1;
  548.  
  549.               // If buffer-writting operation is the last buffer-writting operation then...
  550.               if ((writeCount == writeCounts)) {
  551.                 // Fix buffer size for writting the last buffer-data.
  552.                 bufferLength = Convert.ToInt32(chunkSize - sizeWritten);
  553.               }
  554.  
  555.               // Read bytes from the input file).
  556.               buffer = binaryReader.ReadBytes(bufferLength);
  557.  
  558.               // Write those bytes in the chunk file.
  559.               outputStream.Write(buffer, 0, buffer.Length);
  560.  
  561.               // Increment the bytes-written counter.
  562.               sizeWritten += buffer.Length;
  563.  
  564.               // Decrease the bytes-remaining counter.
  565.               sizeRemaining -= buffer.Length;
  566.  
  567.               // Set the total progress.
  568.               totalProgress = (totalSize - sizeRemaining) * (100 / totalSize);
  569.  
  570.               // Set the current chunk progress.
  571.               chunkProgress = !(chunkIndex == chunkCount) ? (100 / chunkSize) * (sizeWritten - bufferLength) : (100 / (inputStream.Length - (chunkSize * (chunkIndex - 1)))) * (sizeWritten - bufferLength);
  572.  
  573.               // Set the progress event data.
  574.               progressArguments = new SplitProgressChangedArgs(TotalProgress: !(totalProgress > 99.9) ? totalProgress : 99.9, ChunkProgress: chunkProgress, ChunksToCreate: chunkCount, ChunksCreated: chunkIndex - 1L);
  575.  
  576.               // Trigger the progress event.
  577.               if (SplitProgressChanged != null) {
  578.                 SplitProgressChanged(this, progressArguments);
  579.               }
  580.  
  581.             }
  582.             // (inputStream.Position < inputStream.Length) AndAlso (sizeWritten < chunkSize)
  583.  
  584.             outputStream.Flush();
  585.  
  586.           }
  587.           // outputStream
  588.  
  589.         }
  590.         // (inputStream.Position < inputStream.Length)
  591.  
  592.       }
  593.       // binaryReader
  594.  
  595.     }
  596.     // inputStream
  597.  
  598.     // Set the ending progress event data.
  599.     progressArguments = new SplitProgressChangedArgs(TotalProgress: 100.0, ChunkProgress: 100.0, ChunksToCreate: chunkCount, ChunksCreated: chunkIndex - 1L);
  600.  
  601.     // Trigger the last progress event.
  602.     if (SplitProgressChanged != null) {
  603.       SplitProgressChanged(this, progressArguments);
  604.     }
  605.  
  606.   }
  607.  
  608.   /// <summary>
  609.   /// Merges the chunks of a previously splitted file.
  610.   /// </summary>
  611.   /// <param name="sourceChunk">The initial chunk of a splitted file. (eg: 'C:\File.Part.01.avi')</param>
  612.   /// <param name="targetFile">The target filepath.</param>
  613.   /// <param name="overwrite">
  614.   /// If set to <c>true</c>, in case that the specified file in <paramref name="targetFile"/> exists it will be overwritten,
  615.   /// otherwise, an exception will be thrown.
  616.   /// </param>
  617.   /// <param name="deleteChunksAfterMerged">If set to <c>true</c>, the chunks will be deleted after a successful merge operation.</param>
  618.   /// <exception cref="System.IO.FileNotFoundException">The specified chunk file doesn't exists.</exception>
  619.   /// <exception cref="System.IO.FileNotFoundException">Only one chunk file found, the last chunk file is missing.</exception>
  620.   /// <exception cref="System.IO.IOException">The specified target file already exists.</exception>
  621.   /// <exception cref="System.OverflowException">"Unexpected chunk filesize-count detected, maybe one of the chunk files is corrupt?.".</exception>
  622.   public void Merge(string sourceChunk, string targetFile = null, bool overwrite = false, bool deleteChunksAfterMerged = false)
  623.   {
  624.     if (!File.Exists(sourceChunk)) {
  625.       throw new FileNotFoundException("The specified chunk file doesn't exists.", sourceChunk);
  626.       return;
  627.  
  628.     } else if (!overwrite && File.Exists(targetFile)) {
  629.       throw new IOException(string.Format("The specified target file already exists: {0}", targetFile));
  630.       return;
  631.  
  632.     }
  633.  
  634.     // The progress event arguments.
  635.     MergeProgressChangedArgs progressArguments = null;
  636.  
  637.     // FileInfo instance of the source chunk file.
  638.     FileInfo fInfo = new FileInfo(sourceChunk);
  639.  
  640.     // Get the source chunk filename without extension.
  641.     string filename = Path.GetFileNameWithoutExtension(fInfo.FullName);
  642.     // Remove the chunk enumeration from the filename.
  643.     filename = filename.Substring(0, filename.LastIndexOf('.'));
  644.  
  645.     // Set the enumeration pattern to find the chunk files to merge.
  646.     string chunkPatternSearch = filename + ".*" + !string.IsNullOrEmpty(fInfo.Extension) ? fInfo.Extension : "";
  647.  
  648.     // Retrieve all the chunk files to merge.
  649.     IEnumerable<FileInfo> chunks = from chunk in Directory.EnumerateFiles(fInfo.DirectoryName, chunkPatternSearch, SearchOption.TopDirectoryOnly)new FileInfo(chunk);
  650.  
  651.     // If chunk files are less than two then...
  652.     if (chunks.LongCount < 2L) {
  653.       throw new FileNotFoundException("Only one chunk file found, the last chunk file is missing.");
  654.       return;
  655.     }
  656.  
  657.     // The total filesize to merge, in bytes.
  658.     long totalSize = (from Chunk in chunkschunk.Length).Sum;
  659.  
  660.     // Gets the filesize of the chunk files and the last chunk file, in bytes.
  661.     long[] chunkSizes = (from Chunk in chunkschunk.Lengthorderby Length descending).Distinct.ToArray;
  662.  
  663.     // If chunk sizes are more than 2...
  664.     if (chunkSizes.LongCount > 2L) {
  665.       throw new OverflowException("Unexpected chunk filesize-count detected, maybe one of the chunk files is corrupt?.");
  666.       return;
  667.     }
  668.  
  669.     // The remaining size to calculate the percentage, in bytes.
  670.     long sizeRemaining = totalSize;
  671.  
  672.     // Counts the length of the current chunk file to calculate the percentage, in bytes.
  673.     long sizeWritten = 0;
  674.  
  675.     // Counts the length of the written size on the current chunk file, in bytes.
  676.     long chunkSizeWritten = 0;
  677.  
  678.     // The buffer to read data and merge the chunks.
  679.     byte[] buffer = null;
  680.  
  681.     // The buffer length.
  682.     int bufferLength = this.BufferSize;
  683.  
  684.     // The total amount of chunks to merge.
  685.     long chunkCount = chunks.LongCount;
  686.  
  687.     // Keeps track of the current chunk.
  688.     long chunkIndex = 0;
  689.  
  690.     // Keeps track of the total percentage done.
  691.     double totalProgress = 0;
  692.  
  693.     // Create the output file to merge the chunks inside.
  694.     using (FileStream outputStream = new FileStream(targetFile, FileMode.Create)) {
  695.  
  696.       // Iterate the chunk files.
  697.  
  698.       foreach (FileInfo chunk in chunks) {
  699.         // Open the chunk file to start reading bytes.
  700.         using (FileStream inputStream = new FileStream(chunk.FullName, FileMode.Open)) {
  701.  
  702.           using (BinaryReader binaryReader = new BinaryReader(inputStream)) {
  703.  
  704.             // Read until reached the end-bytes of the chunk file.
  705.  
  706.             while ((inputStream.Position < inputStream.Length)) {
  707.               // Read bytes from the chunk file (BufferSize byte-length).
  708.               buffer = binaryReader.ReadBytes(bufferLength);
  709.  
  710.               // Write those bytes in the output file.
  711.               outputStream.Write(buffer, 0, buffer.Length);
  712.  
  713.               // Increment the bytes-written counters.
  714.               sizeWritten += buffer.Length;
  715.               chunkSizeWritten += buffer.Length;
  716.  
  717.               // Decrease the bytes-remaining counter.
  718.               sizeRemaining -= buffer.Length;
  719.  
  720.               // Set the total progress.
  721.               totalProgress = (totalSize - sizeRemaining) * (100 / totalSize);
  722.  
  723.               // Set the progress event data.
  724.               progressArguments = new MergeProgressChangedArgs(TotalProgress: !(totalProgress > 99.9) ? totalProgress : 99.9, ChunkProgress: (100 / inputStream.Length) * (chunkSizeWritten - bufferLength), ChunksToMerge: chunkCount, ChunksMerged: chunkIndex);
  725.  
  726.               // Trigger the progress event.
  727.               if (MergeProgressChanged != null) {
  728.                 MergeProgressChanged(this, progressArguments);
  729.               }
  730.  
  731.             }
  732.             // (inputStream.Position < inputStream.Length)
  733.  
  734.             chunkIndex += 1;
  735.             // Increment the chunk file counter.
  736.             chunkSizeWritten = 0L;
  737.             // Reset the bytes-written for the next chunk.
  738.  
  739.           }
  740.           // binaryReader
  741.  
  742.         }
  743.         // inputStream
  744.  
  745.       }
  746.  
  747.       outputStream.Flush();
  748.  
  749.     }
  750.     // outputStream
  751.  
  752.     // Set the ending progress event data.
  753.     progressArguments = new MergeProgressChangedArgs(TotalProgress: 100.0, ChunkProgress: 100.0, ChunksToMerge: chunkCount, ChunksMerged: chunkIndex - 1L);
  754.  
  755.     // Trigger the last progress event.
  756.     if (MergeProgressChanged != null) {
  757.       MergeProgressChanged(this, progressArguments);
  758.     }
  759.  
  760.     // Delethe the chunk files.
  761.     if (deleteChunksAfterMerged) {
  762.  
  763.       foreach (FileInfo chunk in chunks) {
  764.         File.Delete(chunk.FullName);
  765.       }
  766.  
  767.     }
  768.     // deleteChunksAfterMerged
  769.  
  770.   }
  771.  
  772.   #endregion
  773.  
  774.   #region " Hidden Methods "
  775.  
  776.   /// <summary>
  777.   /// Serves as a hash function for a particular type.
  778.   /// </summary>
  779.   [EditorBrowsable(EditorBrowsableState.Never)]
  780.   public new int GetHashCode()
  781.   {
  782.     return base.GetHashCode;
  783.   }
  784.  
  785.   /// <summary>
  786.   /// Gets the System.Type of the current instance.
  787.   /// </summary>
  788.   /// <returns>The exact runtime type of the current instance.</returns>
  789.   [EditorBrowsable(EditorBrowsableState.Never)]
  790.   public new Type GetType()
  791.   {
  792.     return base.GetType;
  793.   }
  794.  
  795.   /// <summary>
  796.   /// Determines whether the specified System.Object instances are considered equal.
  797.   /// </summary>
  798.   [EditorBrowsable(EditorBrowsableState.Never)]
  799.   public new bool Equals(object obj)
  800.   {
  801.     return base.Equals(obj);
  802.   }
  803.  
  804.   /// <summary>
  805.   /// Determines whether the specified System.Object instances are the same instance.
  806.   /// </summary>
  807.   [EditorBrowsable(EditorBrowsableState.Never)]
  808.   private new bool ReferenceEquals(object objA, object objB)
  809.   {
  810.     return null;
  811.   }
  812.  
  813.   /// <summary>
  814.   /// Returns a String that represents the current object.
  815.   /// </summary>
  816.   [EditorBrowsable(EditorBrowsableState.Never)]
  817.   public new string ToString()
  818.   {
  819.     return base.ToString;
  820.   }
  821.  
  822.   #endregion
  823.  
  824. }
  825.  
  826. //=======================================================
  827. //Service provided by Telerik (www.telerik.com)
  828. //=======================================================
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement