Splitting and joining files using C#

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);

    }

}
Nathan Pakovskie is an esteemed senior developer and educator in the tech community, best known for his contributions to Geekpedia.com. With a passion for coding and a knack for simplifying complex tech concepts, Nathan has authored several popular tutorials on C# programming, ranging from basic operations to advanced coding techniques. His articles, often characterized by clarity and precision, serve as invaluable resources for both novice and experienced programmers. Beyond his technical expertise, Nathan is an advocate for continuous learning and enjoys exploring emerging technologies in AI and software development. When he’s not coding or writing, Nathan engages in mentoring upcoming developers, emphasizing the importance of both technical skills and creative problem-solving in the ever-evolving world of technology. Specialties: C# Programming, Technical Writing, Software Development, AI Technologies, Educational Outreach

Leave a Reply

Your email address will not be published. Required fields are marked *

Back To Top