Reputation: 529
I'm trying to make a file splitter/joiner in C++ and I have trouble with my split function. I used an MP4 file for a quick test and the result was: every other parts are OK but the last part always doesn't work. I don't understand this. Can anyone please explain it to me? Here is my split function:
void split_F(const char* file_name, int number_of_part)
{
FILE *fp_read = fopen(file_name, "rb");
//calculate file size
int file_size;
fseek(fp_read, 0L, SEEK_END);
file_size = ftell(fp_read);
rewind(fp_read); //reset file pointer
//calculate number of parts
//int number_of_part = (int)ceil((double)file_size / size_of_part);
long size_of_part;
size_of_part = (int)floor((double)file_size / number_of_part);
cout << "Total files after split: " << number_of_part << endl
<< "...Processing..." << endl;
//main process
char name[255] = "";
for (int count = 1; count <= number_of_part; count++)
{
sprintf(name, "%s.part_%03d", file_name, count);
FILE *fp_write = fopen(name, "wb");
//create buffer
char *buffer = new char[size_of_part];
memset(buffer, NULL, size_of_part); //reset buffer
fread(buffer, size_of_part, 1, fp_read);
fwrite(buffer, size_of_part, 1, fp_write);
fseek(fp_read, count*size_of_part, SEEK_SET);
cout << "> File: " << name << " done babe!" << endl;
delete[] buffer;
fclose(fp_write);
}
fclose(fp_read);
}
Upvotes: 0
Views: 1548
Reputation: 9570
Your file may not divide into N parts of equal lengths (suppose the file is 7 bytes long and you divide it into 3 parts...?)
long remaining_size = file_size;
long size_of_part;
size_of_part = (file_size + number_of_part - 1) / number_of_part;
This makes the part length rounded up, so possibly the last part will be shorter than all preceding parts.
//create buffer
char *buffer = new char[size_of_part];
//main process
char name[255] = "";
for (int count = 1; count <= number_of_part; count++)
{
sprintf(name, "%s.part_%03d", file_name, count);
FILE *fp_write = fopen(name, "wb");
long this_part_size =
remaining_size < size_of_part ? remaining_size : size_of_part;
fread(buffer, this_part_size, 1, fp_read);
fwrite(buffer, this_part_size, 1, fp_write);
cout << "> File: " << name << " done babe!" << endl;
fclose(fp_write);
remaining_size -= this_part_size;
}
delete[] buffer;
Upvotes: 0
Reputation: 9292
The last part will be potentially smaller or larger than size_of_part, as the original file size is not a multiple of it.
You need to adapt the size of the last part automatically.
For instance, if you have a file size of 1000 bytes, and 7 parts. Your computed file size will be 142. 7*142 = 994, you are missing the last 6 bytes. Is this your problem?
The fseek is not required, why are you using it? You just need to read the input file sequentially
void split_F(const char* file_name, int number_of_part)
{
FILE *fp_read = fopen(file_name, "rb");
//calculate file size
int file_size;
fseek(fp_read, 0L, SEEK_END);
file_size = ftell(fp_read);
rewind(fp_read); //reset file pointer
//calculate number of parts
long size_of_part;
size_of_part = (int)ceil((double)file_size / number_of_part);
cout << "Total files after split: " << number_of_part << endl
<< "...Processing..." << endl;
//main process
char name[255] = "";
int bytesRemaining = file_size;
//create buffer, we reuse it for each part
char *buffer = new char[size_of_part];
//No need to reset buffer
//memset(buffer, NULL, partSize);
for (int count = 1; count <= number_of_part; count++)
{
sprintf(name, "%s.part_%03d", file_name, count);
FILE *fp_write = fopen(name, "wb");
int partSize;
if(bytesRemaining > size_of_part)
{
partSize = size_of_part;
}
else
{
partSize = bytesRemaining;
}
fread(buffer, partSize, 1, fp_read);
fwrite(buffer, partSize, 1, fp_write);
cout << "> File: " << name << " done babe!" << endl;
fclose(fp_write);
}
fclose(fp_read);
delete[] buffer;
}
Upvotes: 1
Reputation: 154911
You are calculating size_of_part
as a rounded quotient of file size and the requested number of parts. You then proceed to read the file in chunks of that exact size. This will fail unless the file size is a multiple of number_of_parts
. You need to fix your code to allow the last part to be smaller than size_of_part
.
Upvotes: 0