Reputation: 4454
I have two functions. One copies text files which uses the "r"
and "w"
modes for reading and writing, and one that copies binary files which uses the "rb"
and "wb
" modes.
But if I were to use these functions, I have to determine first whether the file that I want to duplicate is a text or binary file. I want a solution that allows me to copy a file successfully without knowing previously the nature of the file. A single function that deals with this matter. Any ideas?
P.S : I noticed that ctrl + c
copy is faster than my function, so tips to improve the speed of the function are also welcome.
#include <stdio.h>
void copyfile_txt(const char *inputfile, const char *outputfile);
void copyfile_bin(const char *inputfile, const char *outputfile);
int main(void)
{
copyfile_txt("file_input.txt", "file_output.txt");
copyfile_bin("ubuntu-14.04.3-desktop-amd64.iso", "Ubuntu.iso");
return 0;
}
long GetFileSize(FILE *fp)
{
fseek(fp, 0L, SEEK_END);
long sz = ftell(fp);
fseek(fp, 0L, SEEK_SET);
return sz;
}
void copyfile_txt(const char *inputfile, const char *outputfile)
{
static FILE *fp_I;
static FILE *fp_O;
fp_I = fopen(inputfile, "r");
if (!fp_I) {
perror(inputfile);
return;
}
fp_O = fopen(outputfile, "w");
if (!fp_O) {
fclose(fp_I);
perror(outputfile);
return;
}
static int c;
while ((c = getc(fp_I)) != EOF) {
putc(c, fp_O);
}
fclose(fp_I);
fclose(fp_O);
}
void copyfile_bin(const char *inputfile, const char *outputfile)
{
static FILE *fp_I;
static FILE *fp_O;
fp_I = fopen(inputfile, "rb");
if (!fp_I) {
perror(inputfile);
return;
}
fp_O = fopen(outputfile, "wb");
if (!fp_O) {
fclose(fp_I);
perror(outputfile);
return;
}
static int c;
static long n;
static long sz;
n = 0;
sz = GetFileSize(fp_I);
while (n++ < sz) {
c = getc(fp_I);
putc(c, fp_O);
}
fclose(fp_I);
fclose(fp_O);
}
Upvotes: 5
Views: 794
Reputation: 144770
You do not need to make a special case of text files, copy all files as binary. This is what most file copying utilities do.
Note however that your binary file copying function has problems:
There is no need to compute the file size, copying until you get EOF
is correct and allows you to copy files larger than LONG_MAX
.
There is no need for static variables: using static
variables makes your function fail if used from multiple threads.
It would be useful to return a completion code.
Here is a simpler version:
int copyfile_bin(const char *inputfile, const char *outputfile) {
FILE *fp_I;
FILE *fp_O;
fp_I = fopen(inputfile, "rb");
if (!fp_I) {
perror(inputfile);
return -1;
}
fp_O = fopen(outputfile, "wb");
if (!fp_O) {
fclose(fp_I);
perror(outputfile);
return -1;
}
int c;
while ((c = getc(fp_I)) != EOF) {
putc(c, fp_O);
}
fclose(fp_I);
if (fclose(fp_O) != 0) {
perror(outputfile);
return -1;
}
return 0;
}
To improve speed, you could increase the buffer sizes with setvbuf()
or use fread()
and fwrite()
with a large allocated buffer.
For a faster inner loop, use this:
size_t nr, size = 1024 * 1024;
void *buffer = malloc(size);
if (buffer != NULL) {
while ((nr = fread(buffer, 1, size, fp_I)) > 0) {
if (fwrite(buffer, 1, nr, fp_O) != nr) {
fprintf(stderr, "write error: ");
perror(outputfile);
free(buffer);
fclose(fp_I);
fclose(fp_O);
return -1;
}
}
if (ferror(fp_I)) {
fprintf(stderr, "read error: ");
perror(inputfile);
free(buffer);
fclose(fp_I);
fclose(fp_O);
return -1;
}
free(buffer);
} else {
/* use the regular getc/putc loop */
int c;
while ((c = getc(fp_I)) != EOF) {
putc(c, fp_O);
}
}
Upvotes: 6