Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#3.5

J-AXE: A File Splitter in C#

4.15/5 (9 votes)
12 Jul 2011CPOL6 min read 37.4K   2K  
J-AXE file splitter is a Windows application developed using C# .NET to split file into time interval based on size and total files after splits.

Introduction

J-AXE file splitter is a Windows application developed using C# .NET to split file into time interval based on size and total files after splits. I would not ignore the fact that this is some kind of new application. Already there are so many open source projects available to achieve the same purpose. Then the question is why I have spent lots of time to develop this app: allow me to explain the question: whatever application is available as open and/or paid, you will not get the options to split the file based on Time interval or duration. But here you will get this functionality along with other functionality with new flavor; and the main point is that I wanted to develop this using C#. NET and by developing this kind of application I will get a chance to learn something new and even I would utilize my free time into something productive. So I did this and here is the UI of this J-AXE file splitter application.

UI.png

Fig 1. JAXE File Splitter UI.

You might wonder why this application is named J-AXE? Actually the letter J came from Jawed and AXE is to cut some wooden block. So, I have chosen this application name as J-AXE.

Background

Of course, there was something which triggered me to come up with this ideas/application. Last month, I recorded family videos using my camcorder. After that, I added few songs and effects into the recorded video to make it into a movie so that I could distribute this among family members. Now I wanted to split this file into durations instead of size so that I could make it into different parts, something like Part 1 as 30 minutes and Part 2 as 45 Minutes. I searched here and there for open source but everything I got had functionality to splits file only by size not by the time interval.

Then this requirement triggered some chemical imagination into my mind to come up with some application to fulfill my requirement and here it is an application “J-AXE: A file Splitter”.

Using the Code

J-AXE: A file Splitter Windows application is very handy in use. The whole solution is divided into 2 projects. One project would be User interface and the second project would be nothing but our main logic which is in DLL format. The idea to separate logic from UI and make logic as DLL so that anybody can use it easily without referring to my UI implementation.

Let me give you some pictorial presentation of the whole scenario (Class Diagram):

ClassDiagram.png

Fig 2. Class Diagram of JAXE File Splitter with JAXE DLL.

First, I would like to explain the implementation of UI part. Then, I will explain the Logic part.

PART 1: User Interface

The block diagram would be something like this:

JAXE-FileSplitter_New.png

Fig 3. Block Digaram of JAXE File Splitter.

On UI User will get the below option to split the file:

  • Based on Duration (Time duration in sec/min)
  • Size (in Bytes/KB/MB)
  • And Number of files

Based on the option selected, we will call the corresponding function to splits the file:

Here is the code to call the corresponding method:

On click of Split Button, we will call the button click event function to get the inputs values like Location of file to splits, Output directory and selected Option.

C#
//get the tab selected
int tabSelected = tabControlDuration.SelectedIndex;
//make sure that inputs file and target folder name is provided
if (!string.IsNullOrEmpty(textBoxFileSplit.Text))
{
if (!string.IsNullOrEmpty(textBoxOpFileLocation.Text))
{//get the tab selected for the operation
switch (tabSelected)
{
case 0:
DurationSplit();//call the method to split the file based on duration.
break;
case 1:
SizeSplit();//call the method to split the file based on Size in KB/M/Bytes.
break;
case 2:
NoOfFileSplit();//Call the method to split the the file based on Numbers.
break;
default:
break;
}//end of switch

Let’s assume that user has clicked on Duration Tab:

Under this option, user needs to provide the Time interval (like 30 minutes of interval) to split the file along with whether they wants the time interval in Minutes or seconds (By default, it would be in seconds). After providing the desired inputs, user needs to click on Split button. On click of this split button, user can see animation of AXE on UI, like something is under AXE. To show the Animation on UI and splitting of files, I have used the concept of BACKGROUND Worker. So that while splitting of the file going on the UI will not get frozen or hang.

Allow me to explain something about background worker (Source: http://www.albahari.com/threading/part3.aspx).

Background worker is part of System.ComponentModel namespace for managing a worker thread.

BackgroundWorker is a component that allows you to delegate a long running task to a different thread. It doesn’t stop with that. You can place the component on a Windows Form (it is a non-UI control, so it goes into the component tray). You can register event handlers with it. It takes care of running the long running task in a separate thread while running the task to update control (to report result or progress) in the main event handling thread.

BackgroundWorker has a RunWorkerCompleted event that fires after the DoWork event handler has done its job. On DoWork, the BackgroundWorker will call our JAXE DLL to split the file and when it’s done, it will call RunWorkerCompleted to show notification message to the user through UI and reset all the controls to initial states.

Come to the code part:

If you look at my code, I have used RunWorkerAsync by passing parameter as object. It means I’m telling BackgroundWorker to do work asynchronously. Here is the code to perform our task:

C#
//Method to split the file based on Duration.
private void DurationSplit()
{
var durationIntreval = comboBoxDuration.SelectedIndex;
//Verify the Duration value provided by user
if (!string.IsNullOrEmpty(textBoxDuration.Text))
{
//Convert the duration in seconds
var durationInSeconds = 0.0;
if (durationIntreval == 1)
durationInSeconds=Convert.ToDouble(textBoxDuration.Text)*60;
else
durationInSeconds=Convert.ToDouble(textBoxDuration.Text);
//set the values
var setInPuts = new SetInPuts
{
SourceFileLocation = textBoxFileSplit.Text,
TargetFolderLocation = textBoxOpFileLocation.Text,
DurationToSplit =durationInSeconds,
TabSelected=tabControlDuration.SelectedIndex
}; 
//Enabled the animation
pictureBox1.Visible = true;
//disable the button
buttonSplit.Enabled = false; 
//initialize the BackGround worker
backgroundWorkerForSplitFile = new BackgroundWorker();
//run back ground worker in sync by passing parameter as object.
backgroundWorkerForSplitFile.RunWorkerAsync(setInPuts);
//force the BGW to do some work
backgroundWorkerForSplitFile.DoWork+=new DoWorkEventHandler
			(backgroundWorkerForSplitFile_DoWork);
//Force the GBW to perform some of the task when previous job done
backgroundWorkerForSplitFile.RunWorkerCompleted+=
    new RunWorkerCompletedEventHandler(backgroundWorkerForSplitFile_RunWorkerCompleted);
}//end of if condition
}//end of the method

Our Dowork will go here, which will ultimately get called by background worker.

C#
private static void backgroundWorkerForSplitFile_DoWork
	(object sender, DoWorkEventArgs e)
{
//
var split = new JAXE.Jaxe();
var inputToPass = e.Argument as SetInPuts;
if (inputToPass != null)
{
switch (inputToPass.TabSelected)
{
case 0:
split.SplitFileBasedOnDuration(inputToPass.SourceFileLocation,
	inputToPass.DurationToSplit,inputToPass.TargetFolderLocation);
break;
case 1:
split.SplitFileBasedOnSize(inputToPass.SourceFileLocation, 
	inputToPass.SizeToSplit, inputToPass.TargetFolderLocation);
break;
case 2:
split.SplitFileBasedOnNumberOfFiles(inputToPass.SourceFileLocation, 
	inputToPass.NumOfFileToSplits, inputToPass.TargetFolderLocation);
break;
default:
break;
}
}
}//end of method

On completion, the background worker will call RunWorkerCompleted to update the user with Notification message and alongwith reset all the controls.

Using background worker, we will call our main logic (JAXE DLL) which will content our splits file logic.

If you see the above piece of code, we have called the method like this:

C#
split.SplitFileBasedOnDuration(inputToPass.SourceFileLocation,
	inputToPass.DurationToSplit,inputToPass.TargetFolderLocation);

I have called SplitFileBasedOnDuration method which is part of our JAXE class that resides in our external DLL, to split the file based on time interval.

To get the duration of input file, I have used open source DLL that is nothing but “DirectShowLib”. To know more about this, visit this link. After getting the whole duration, I have started splitting the file into time intervals.

To split the file based on duration, I have taken the reference with respect to size of input size. Just have a look at the below code.

C#
//Open the file in read mode
var fsDur = new FileStream(inputFile, FileMode.Open, FileAccess.Read);
//variable to store inputs file total length in seconds
var totalDuration = 0.0;
//get the length of file in seconds 
GetVideoLength(inputFile, out totalDuration);

Duration of each byte.

C#
//get the duration of each in interval to split
var durationOfEachFile = Convert.ToDouble(timeDuration);
//get the duration of 1 bytes file
var fractionOfTimeDuration = totalDuration / durationOfEachFile;  

Size of file corresponding to each byte w.r.t. time duration provided by User:

C#
//get the size corresponding to duration to split the file
var sizeOfEachFile = (int)Math.Ceiling((double)fsDur.Length / fractionOfTimeDuration);

Now we will get the Total Numbers of files after splitting the source file.

C#
//get the total file to split after comparing time interval with size
var numberOfFiles = (int)Math.Ceiling((double)fsDur.Length / sizeOfEachFile);
//the base file name
var baseFileName = Path.GetFileNameWithoutExtension(inputFile);
//get the extension of the file
var extension = Path.GetExtension(inputFile);

Finally, we will start reading the source file byte by byte and will place into output file:

C#
for (var i = 1; i <= numberOfFiles; i++)
{
//file name after splitting
var outputFile = new FileStream(outPutLocation + "\\" 
	+ baseFileName + "_" + i.ToString().PadLeft(5, Convert.ToChar("0")) 
	+ extension, FileMode.Create, FileAccess.Write);
var bytesRead = 0;
//array of bytes to hold the piece of file data after splitting
var buffer = new byte[sizeOfEachFile];
//split the file byte by byte
if ((bytesRead = fsDur.Read(buffer, 0, sizeOfEachFile)) > 0)
outputFile.Write(buffer, 0, bytesRead);
outputFile.Close();
}

The output files name would in this format SourceFilename_Numericvalue.extension.

The whole logic would be as below:

C#
//Split the file based on duration
//Note: There might be a chances where exact duration of the file 
//would not be same as user provided. deviation of few seconds
public void SplitFileBasedOnDuration(string inputFile, 
		double timeDuration,string outPutLocation)
{
//Open the file in read mode
var fsDur = new FileStream(inputFile, FileMode.Open, FileAccess.Read);
//variable to store inputs file total length in seconds
var totalDuration = 0.0;
//get the length of file in seconds 
GetVideoLength(inputFile, out totalDuration);
//get the duration of each in interval to split
var durationOfEachFile = Convert.ToDouble(timeDuration);
//get the duration of 1 bytes file
var fractionOfTimeDuration = totalDuration / durationOfEachFile; 
//get the size corresponding to duration to split the file
var sizeOfEachFile = (int)Math.Ceiling((double)fsDur.Length / fractionOfTimeDuration);
//get the total file to split after comparing time interval with size
var numberOfFiles = (int)Math.Ceiling((double)fsDur.Length / sizeOfEachFile);
//the base file name
var baseFileName = Path.GetFileNameWithoutExtension(inputFile);
//get the extension of the file
var extension = Path.GetExtension(inputFile);
for (var i = 1; i <= numberOfFiles; i++)
{
//file name after splitting
var outputFile = new FileStream(outPutLocation + 
	"\\" + baseFileName + "_" + i.ToString().PadLeft(5, Convert.ToChar("0")) + 
	extension, FileMode.Create, FileAccess.Write);
var bytesRead = 0;
//array of bytes to holed the piece of file data after splitting
var buffer = new byte[sizeOfEachFile];
//split the file byte by byte
if ((bytesRead = fsDur.Read(buffer, 0, sizeOfEachFile)) > 0)
outputFile.Write(buffer, 0, bytesRead);
outputFile.Close();
}
//close the File stream
fsDur.Close();
//return "Done!";
}

Finally our files would be ready to use after splitting the source file. I have tested this on few extension source files, it works perfectly. But I have not tested this on all types of source files. Might be few files would not work. Please let me know if you find some bugs. I would be happy to hear from all of you.

Points of Interest

The first time I used the concept of background worker and I found it very interesting and useful in Windows application when you don’t want your UI to get frozen while doing some complex/lengthy process. Splitting the file based on duration was also very challenging, somehow I overcome those issues, but still there is some deviation (fraction of seconds) in the time duration of output files.

Points to Remember

BackgroundWorker uses the thread pool, which means you should never call Abort on a BackgroundWorker thread.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)