Click here to Skip to main content
15,867,756 members
Articles / Desktop Programming / MFC
Article

File Splitting/Mending Classes

Rate me:
Please Sign up or sign in to vote.
4.24/5 (10 votes)
28 Oct 20048 min read 50.8K   779   24   9
An article providing classes to split and mend files.

Introduction

This class gives you the ability to easily split or mend files. I've come across people all over the web looking for classes and documentation to help them with file splitting code and concepts. However, there is an extreme lack of quality file splitting resources, including classes to provide quick and easy solutions. So, I created this class pair to aid in the development of programs which require file splitting and/or mending operations.

Using the code

There are two classes included with this article; CFileSplit is used for splitting, and CFileMend is for mending files back together. These two classes are independent of each other, meaning you don't have to include both in your project if you'd only like to use one. However, when using either class, you must include the CFileSplitShared.h header file within your project.

CFileSplit

First, we'll look over the CFileSplit class to see what it does and how to use it. As the name obviously indicates, this class is what we use for splitting files. To use it, you'll need to include the CFileSplit.h and CFileSplitShared.h header files. So let's dive in, shall we?

Class Construction

CFileSplit contains three available constructors, below are examples of each:

// If you'd like to construct the class without
// assigning an owner window, you'd use: 
CFileSplit cfsMySplit;

// To assign an owner to the class, use the following,
// where hWndOwner is the owner window's handle:
CFileSplit cfsMySplit(hWndOwner);

// To specify the file to split now instead of later:
CFileSplit cfsMySplit("C:\\Example\\File.ext", hWndOwner);

Specifying the File to Split

There are two ways to designate the file to split, you may use the constructor above to specify the file, or you can call SetFilePath to pass the file's location. Both should take an absolute path (relative paths work, but aren't very safe), and the file must exist prior to providing the file's path. SetFilePath will return true on success and false on failure.

Specifying the Destination Folder

Setting a destination directory is very simple, all you have to do is call the SetDestPath member function with the output directory path. Note: If the path does not exist when the Split() function is executed, the directory will be created.

cfsMySplit.SetDestPath("C:\\MyFilePieces\\");

Setting the Size of Each Split Piece

CFileSplit offers two different ways to set the size of each split, either you can set the file size or assign a certain number of splits to create. To set the file size to split the file to, use the SetSplitSize function, which has a sole parameter that takes the split size in bytes. If you'd like to split the file into a predetermined amount of splits and let CFileSplit do the file size calculation, then pass the number of splits you want to create to SetPieceCount. Each will cancel the prior size; for example, if you set the size using SetSplitSize, and then SetPieceCount, SetSplitSize will be overridden and the supplied piece count will be used instead. Here are some quick examples of how to use each:

cfsMySplit.SetSplitSize(512000); // Set the split size to 500 kilobytes
cfsMySplit.SetPieceCount(3); // Or split the file into 3 pieces instead

Function to Handle Splitting Progress (Optional)

Often, you'll probably want to update a progress bar or execute other functions during the splitting process. This can be achieved by setting the split handler using SetSplitHandler. SetSplitHander takes two parameters, the first is the function to call, which is in the form of functionname(__int64 variable), the second parameter is the amount of bytes to read/write while splitting before calling the function each time. So, if you wanted to execute the function for every 1 kilobytes that are processed during splitting, you set the second parameter to 1024. The only limitation is that size isn't always exact, as it is compared each time the buffer is read to.

The function that you specify as the handler, is passed the total amount of bytes processed when the function is called (which will equal the original file size when the splitting is complete).

// This example wouldn't be very practical, because the message box would be
// displayed every time the handler was called while the bytes were
// greater than 500000000000, but it gives you an idea of how it works.

void SplitHandler(__int64 iBytesProcessed) {

    if (iBytesProcessed > 500000000000) {
        MessageBox(NULL, "Wow! This is a big file...", "Wow!", MB_OK);
    }

    // Do other stuff...
}

// To set the above function as the handler, you'd use something like this
// after declaring a CFileSplit variable:

cfsMySplit.SetSplitHandler(SplitHander, 10240);
// Call the handler for every 10 kilobytes processed

Splitting the File

When it comes down to splitting the file, all you have to do is execute the class' Split() function, which returns true on success and false on failure. Below is a full example of a simple splitting operation on a file, from start to finish:

CFileSplit cfsMySplit;

// Specify path of file to split:
if (!cfsMySplit.SetFilePath("C:\\Projects\\MyFile.exe")) {

    TODO: Halt function after displaying message box
    MessageBox(NULL, "Error: File does not exist", 
                     "An error has occurred", MB_ICONHAND);
}

// Set the destination folder
cfsMySplit.SetDestPath("C:\\MySplits\\");

// Assign a split size of 100 kb
cfsMySplit.SetSplitSize("102400");

if (cfsMySplit.Split()) {
    MessageBox(NULL, "File split successful!", "Success", MB_OK);
} else {
    MessageBox(NULL, "File split failed.", 
                     "An error has occurred", MB_ICONHAND);
}

CFileMend

Now that you know how to split files, we'll take a look at how to mend the pieces back together using CFileMend.

Class Construction

CFileMend has one and only one lonely constructor, it has an optional parameter for the owner window's handle, which is only used for passing window error messages (most likely you don't need it).

Specifying a File to Mend

CFileMend provides two different ways to mend files; either by directing CFileMend to a standard split file (created by CFileSplit or any other program that uses the .00* extension form), or by "Pushing" the files into a destination file. If you're interested in pushing the files instead (not standard), then you'll want to refer to the PushFile documentation further into this article.

Anyway, back to specifying a file using standard mending... You have to pass one split piece path to the SetPiecePath, it doesn't matter which one. The path needs to be the full absolute path as relative paths are not always safe. SetPiecePath returns true on success and false on failure.

if (cfmMyMend.SetPiecePath("C:\\MySplits\\MyFile.ext.001")) {
    // Success...
} else {
    // Failure...
}

Specifying the Destination Path

You can set the destination directory path by using SetDestPath, which has the same parameters and result as the CSplitFile counterpart. Note: this should only be the path to the folder you'd like the file to be restored in, it should not include the desired filename.

cfmMyMend.SetDestPath("C:\\MyRestored\\");

Function to Handle Mending Progress (Optional)

CFileMend's mending handler works in the exact same way as CFileSplit's SetSplitHandler function, except you use SetMendHandler and the function is called during the mending process. For more documentation on these functions, see the SetSplitHandler info.

Mending the Files

Like I mentioned earlier, there are two ways to mend files, using the standard extension form or using PushFile. First, we'll go over splitting standard split files. Standard files are those which have been created with a program or class such as CFileSplit, they are standard because they have a three character extension that begins with .001 and continues to increase for each split file. For example, myfile.001 and myfile.002 are standard, however myfile.piece_1 is not.

To mend a standard file, you use the Mend function, which has an optional parameter for setting the restored file's name. If the parameter is not supplied, the file will be created with its original name. Below is a full example of how to mend a set of split files:

CFileMend cfmMyMend;

// Set the file to restore, in this case
// we are mending all MyFile.ext pieces:

if (!cfmMyMend.SetPiecePath("C:\\MySplits\\MyFile.ext.001")) {

    //TODO: Halt function after displaying message box
    MessageBox(NULL, "Error: File does not exist", 
                     "An error has occurred", MB_ICONHAND);
} 

// Set the destination path:
cfmMyMend.SetDestPath("C:\\MyRestored\\");

if (cfmMyMend.Mend()) {
    MessageBox(NULL, "Mending completed successfully!", 
                     "Success!", MB_OK);
} else {
    MessageBox(NULL, "Mending failed.", "Failure.", B_ICONHAND);
}

That is all you need to do to mend a set of standard split files, but what about non-standard files? Well, then you're introduced to three new CFileMend member functions: Open, PushFile and Close.

  • Open - Opens the destination file, this takes one parameter which is the path to the file you'd like to create. Returns true on success, and false on failure.
  • PushFile - Appends a file to the open destination file, the only parameter takes a path to the existing file to append. You must have used Open to open a destination file before pushing any files. Returns true on success, and false on failure.
  • Close - Closes the open destination file, this is called by default in CFileMend's deconstructor, but should be called after you've finished pushing files to the destination file.

Here is a full example, which mends three files together to form MyFile_Mended.ext:

CFileMend cfmMyMend;

if (!cfmMyMend.Open("C:\\MyRestored\\MyFile_Mended.ext")) {
    // Error: Unable to create MyFile.ext
}

// To conserve line usage in this example, error checking is not
// shown. Remember, PushFile returns true on success and false on failure.

cfmMyMend.PushFile("C:\\MySplits\\MyFile.ext.piece_01");
cfmMyMend.PushFile("C:\\MySplits\\MyFile.ext.piece_02");
cfmMyMend.PushFile("C:\\MySplits\\MyFile.ext.piece_03");

cfmMyMend.Close();

Error Reporting

Both CFileSplit and CFileMend share the same type of error reporting (actually "types"). In total, there are four ways to handle errors produced while using each class. However, only two will be commonly used... That leaves two forms of error reporting that will most likely not be needed. The first is done by setting an error handler. This can be achieved by passing a function pointer to the classes' SetErrorHandler function. The error handler should be declared as void, and take an unsigned int as a parameter. When an error occurs, the handler is called and the error code is passed. The other type of error reporting that most likely will not be used is done via window messages. Each error message (lParam: FS_ERROR, wParam: errorcode) is sent to the owner window if present, or all top level windows if neither an error handler or owner is available. So that does it for the error handling types that will be used infrequently, but what about the common reporting techniques?

The most basic error reporting comes in the form of true or false (success and failure). All declared bool functions within these classes return such reports. They include functions such as SetFilePath, Mend, Split and so on.

To pinpoint exactly what error occurred, you'll want to make use of the GetLastError() function present in both classes. This will return the error code (unsigned int) of the last occurring error, 0 is returned if no errors have been reported. Below are the error definitions and a short description of each:

#define FS_ERROR_SUCCESS    0    // No reported errors
#define FS_ERROR_NOEXIST    1    // Error: File does not exist
#define FS_ERROR_SPLITLIMIT    2    // Error: Pieces total more than SPLIT_LIMIT 
#define FS_ERROR_INPUTFAILED    3    // Error: Unable to open input file
#define FS_ERROR_OUTPUTFAILED    4    // Error: Unable to open output file
#define FS_ERROR_NOOUTPUT    5    // Error: No output file specified
#define FS_ERROR_WRITEFAILED    6    // Error: Write error occurred
#define FS_ERROR_INVALIDPIECE    7    // Error: Specified piece is not valid

Here is an example of how you might use error reporting with CFileSplit's Split function:

// ...

char *szErrorMsg;

if (!cfsMySplit.Split()) {

    // An error has occured
    switch (cfsMySplit.GetLastError())
    {
        case FS_ERROR_NOEXIST:
            szErrorMsg = "The file to split no longer exists.";
            break;

        case FS_ERROR_INPUTFAILED:
            szErrorMsg = "Unable to open input file.";
            break;

        case FS_ERROR_OUTPUTFAILED:
            szErrorMsg = "Unable to open output file for writing.";
            break;

        case FS_ERROR_WRITEFAILED:
            szErrorMsg = "Writing operation failed during splitting.";
            break;
        default:
            szErrorMsg = "An error has occurred.";
            break;
    }

    MessageBox(NULL, szErrorMsg, "Error!", MB_OK | MB_ICONHAND);
}

// ...

Additional Notes

If you intend to use the same constructed class for separate files, such as splitting three different files with one CFileSplit variable, you may want to use the classes' Reset() function. The Reset function will set all splitting or mending information back to the classes' original values. However, it does not reset handlers, owners and other important information.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
United States United States
Well first of all, it is fairly obvious my name is Stuart Konen (I'm sure 50% of you just took notice), all of my life I've lived on a farm located in Northern Idaho. What shatters the stereotype of rural residence however, is the fact that I'm very active in the technology and programming worlds. I took up the hobby of programming at age 9, at that point it was little language known as Quick Basic *sigh*. Fast forward another 9 years... (Woah... I just realized that's half of my existence. But that's something I'll have to contemplate later, as I have an autobiography to tell).

Now my experience in programming has improved vastly, I've released various technologies and programs and I'm continuing to pump out concepts and systems that are getting glances from all over the world. My weapon of choice is C++, the core language of the majority of freshly released software, it's sleak, mean, and incrediably powerful. On the side I venture into web application development and site design, where my interest lies in PHP. Over the years my project have included everything from Artificial Intelligence to Web Statistic Tracking systems, but that's the past. What matters is the future... Remember that question we were always asked in grade school? Where did we see ourselves in 10 years. Well that question was asked about 8 years ago in my life, so it looks as though I only have two more for planning stages. In two years I see myself plunging into the world of research, creating my own Research and Development firm, aiming to meet the never-ending need for new and superior software and technology. Soon after becoming a multi-billionare I'll pursue my dream of world domination. Nobody is perfect...

Actually when it comes down to things, the money has no meaning. But there you have it, a 5 minute slice of my thoughts and time... If you have any job opportunities or have the slight urge to initiate a conversation with me, it can be done via email: skonen [at] gmail [dot] com

Comments and Discussions

 
GeneralMy vote of 3 Pin
noreply-thephoenixprod18-Jan-12 22:10
noreply-thephoenixprod18-Jan-12 22:10 
Generalgood ,but Pin
whb1236287-Jul-06 14:41
whb1236287-Jul-06 14:41 
GeneralRe: good ,but Pin
nothing161021-Aug-06 23:50
nothing161021-Aug-06 23:50 
GeneralPossible bug in Split function. Pin
JohnEwer28-Jun-05 22:45
JohnEwer28-Jun-05 22:45 
GeneralAmazing Pin
KW-Rix28-Mar-05 16:16
KW-Rix28-Mar-05 16:16 
GeneralRe: Amazing Pin
TheGreatAndPowerfulOz25-Aug-05 12:00
TheGreatAndPowerfulOz25-Aug-05 12:00 
GeneralRe: Amazing Pin
KW-Rix25-Aug-05 15:13
KW-Rix25-Aug-05 15:13 
GeneralCouple Issues Pin
Blake Miller29-Oct-04 4:26
Blake Miller29-Oct-04 4:26 
GeneralRe: Couple Issues Pin
Stuart Konen29-Oct-04 8:09
Stuart Konen29-Oct-04 8:09 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.