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:
CFileSplit cfsMySplit;
CFileSplit cfsMySplit(hWndOwner);
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);
cfsMySplit.SetPieceCount(3);
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).
void SplitHandler(__int64 iBytesProcessed) {
if (iBytesProcessed > 500000000000) {
MessageBox(NULL, "Wow! This is a big file...", "Wow!", MB_OK);
}
}
cfsMySplit.SetSplitHandler(SplitHander, 10240);
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;
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);
}
cfsMySplit.SetDestPath("C:\\MySplits\\");
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")) {
} else {
}
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;
if (!cfmMyMend.SetPiecePath("C:\\MySplits\\MyFile.ext.001")) {
MessageBox(NULL, "Error: File does not exist",
"An error has occurred", MB_ICONHAND);
}
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")) {
}
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()) {
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.
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