This tutorial will teach you how to create a basic file splitter and joiner using C#, byte arrays and file streams. It will allow you to split files into as many output files as you want and then reconstruct the file from the splitted output files.
This applicaton has multiple purposes, but if you are here, you probably already have a reason to be building it; or you just want to learn how bytes and file streams work in C#.
We shall start by designing the form, two GroupBoxes, in the first one we have a TextBox txtSourceFile where we store the path to the file to be splitted, numOutputs that will hold the number of files that we want the source file splitted into, and two buttons btnBrowseFile and btnSplit for browsing for the source file and the other one for calling the actual method that splits the file. The second GroupBox contains a TextBox btnSourceFolder that holds the path to the source folder (where the file that we want joined together are found), and two buttons btnBrowseFolder and btnJoin, that are used for browsing to the folder where the partial files are found, and call the joining function, respectively.
For the FileStream and FileInfo classes we’ll need System.IO so add this using statement:
using System.IO;
Obviously, we start with the splitting method that looks like this:
private void SplitFile(string FileInputPath, string FolderOutputPath, int OutputFiles)
{
// Store the file in a byte array
Byte[] byteSource = System.IO.File.ReadAllBytes(FileInputPath);
// Get file info
FileInfo fiSource = new FileInfo(txtSourceFile.Text);
// Calculate the size of each part
int partSize = (int)Math.Ceiling((double)(fiSource.Length / OutputFiles));
// The offset at which to start reading from the source file
int fileOffset = 0;
// Stores the name of each file part
string currPartPath;
// The file stream that will hold each file part
FileStream fsPart;
// Stores the remaining byte length to write to other files
int sizeRemaining = (int)fiSource.Length;
// Loop through as many times we need to create the partial files
for (int i = 0; i < OutputFiles; i++)
{
// Store the path of the new part
currPartPath = FolderOutputPath + "\\" + fiSource.Name + "." + String.Format(@"{0:D4}", i) + ".part";
// A filestream for the path
if (!File.Exists(currPartPath))
{
fsPart = new FileStream(currPartPath, FileMode.CreateNew);
// Calculate the remaining size of the whole file
sizeRemaining = (int)fiSource.Length - (i * partSize);
// The size of the last part file might differ because a file doesn't always split equally
if (sizeRemaining < partSize)
{
partSize = sizeRemaining;
}
// Write the byte chunk to the part file
fsPart.Write(byteSource, fileOffset, partSize);
// Close the file stream
fsPart.Close();
// Set the new offset
fileOffset += partSize;
}
}
}
It’s pretty much self-explanatory: we create a byte array to hold the file, then loop as many times as the number of splitted files the user wanted and create a partial file in each loop. We do this by writing to a FileStream object. Each loop we start at a different point in the byte array by using the fileOffiset.
Next comes the method that fixes what we broke into pieces in the previous method. This is where we join files:
private void JoinFiles(string FolderInputPath, string FileOutputPath)
{
// Needed to get all files in that directory
DirectoryInfo diSource = new DirectoryInfo(FolderInputPath);
// Filestream to reconstruct the file
FileStream fsSource = new FileStream(FileOutputPath, FileMode.Append);
// Loop through all the files with the *.part extension in the folder
foreach (FileInfo fiPart in diSource.GetFiles(@"*.part"))
{
// Create a byte array of the content of the current file
Byte[] bytePart = System.IO.File.ReadAllBytes(fiPart.FullName);
// Write the bytes to the reconstructed file
fsSource.Write(bytePart, 0, bytePart.Length);
}
// Close the file stream
fsSource.Close();
}
Now let’s call these methods already. First the user would be browsing for the file that he wants to split:
private void btnBrowseFile_Click(object sender, EventArgs e)
{
// Browse for the file that the user wants to split
if (openSource.ShowDialog() == DialogResult.OK)
{
txtSourceFile.Text = openSource.FileName;
}
}
The next thing would be to click the Split button that calls the method that breaks the file into smaller files:
private void btnSplit_Click(object sender, EventArgs e)
{
// Browse for the folder where the splitted files will be saved
if (saveToFolder.ShowDialog() == DialogResult.OK)
{
SplitFile(txtSourceFile.Text, saveToFolder.SelectedPath, (int)numOutputs.Value);
}
}
Now that the file got split into pieces, we can reconstruct him by having the user pick the folder in which he has the smaller files:
private void btnBrowseFolder_Click(object sender, EventArgs e)
{
// Browse for the folder from where open the part files
if (openFolder.ShowDialog() == DialogResult.OK)
{
txtSourceFolder.Text = openFolder.SelectedPath;
}
}
Finally, clicking the Join button will prompt the user to save somewhere the joined file:
private void btnJoin_Click(object sender, EventArgs e)
{
// Prompt the user to choose the folder where he wants to save the reconstructed file
if (saveOutput.ShowDialog() == DialogResult.OK)
{
JoinFiles(txtSourceFolder.Text, saveOutput.FileName);
}
}