Aayman Khalid
Aayman Khalid

Reputation: 468

copying contents of a text file in c

I want to read a text file and transfer it's contents to another text file in c, Here is my code:

             char buffer[100]; 

             FILE*  rfile=fopen ("myfile.txt","r+");
             if(rfile==NULL)
            {
              printf("couldn't open File...\n");
            }


            fseek(rfile, 0, SEEK_END);
            size_t file_size = ftell(rfile);
            printf("%d\n",file_size);
            fseek(rfile,0,SEEK_SET);
            fread(buffer,file_size,1,rfile);


            FILE* pFile = fopen ( "newfile.txt" , "w+" );
            fwrite (buffer , 1 ,sizeof(buffer) , pFile );
            fclose(rfile);
            fclose (pFile);
            return 0;
          } 

the problem that I am facing is the appearence of unnecessary data in the receiving file, I tried the fwrite function with both "sizeof(buffer)" and "file_size",In the first case it is displaying greater number of useless characters while in the second case the number of useless characters is only 3,I would really appreciate if someone pointed out my mistake and told me how to get rid of these useless characters...

Upvotes: 1

Views: 1583

Answers (5)

Jonathan Leffler
Jonathan Leffler

Reputation: 755010

Here is an implementation of an (almost) general purpose file copy function:

void fcopy(FILE *f_src, FILE *f_dst)
{
    char            buffer[BUFSIZ];
    size_t          n;

    while ((n = fread(buffer, sizeof(char), sizeof(buffer), f_src)) > 0)
    {
        if (fwrite(buffer, sizeof(char), n, f_dst) != n)
            err_syserr("write failed\n");
    }
}

Given an open file stream f_src to read and another open file stream f_dst to write, it copies (the remainder of) the file associated with f_src to the file associated with f_dst. It does so moderately economically, using the buffer size BUFSIZ from <stdio.h>. Often, you will find that bigger buffers (such as 4 KiB or 4096 bytes, even 64 KiB or 65536 bytes) will give better performance. Going larger than 64 KiB seldom yields much benefit, but YMMV.

The code above calls an error reporting function (err_syserr()) which is assumed not to return. That's why I designated it 'almost general purpose'. The function could be upgraded to return an int value, 0 on success and EOF on a failure:

enum { BUFFER_SIZE = 4096 };

int fcopy(FILE *f_src, FILE *f_dst)
{
    char            buffer[BUFFER_SIZE];
    size_t          n;

    while ((n = fread(buffer, sizeof(char), sizeof(buffer), f_src)) > 0)
    {
        if (fwrite(buffer, sizeof(char), n, f_dst) != n)
            return EOF;  // Optionally report write failure
    }
    if (ferror(f_src) || ferror(f_dst))
        return EOF;  // Optionally report I/O error detected
    return 0;
}

Note that this design doesn't open or close files; it works with open file streams. You can write a wrapper that opens the files and calls the copy function (or includes the copy code into the function). Also note that to change the buffer size, I simply changed the buffer definition; I didn't change the main copy code. Also note that any 'function call overhead' in calling this little function is completely swamped by the overhead of the I/O operations themselves.

Upvotes: 1

Mayank
Mayank

Reputation: 2220

I think the parameters you passed in the fwrite are not in right sequence.

To me it should be like that-

fwrite(buffer,SIZE,1,pFile)

as the syntax of fwrite is size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

The function fwrite() writes nmemb elements of data, each size bytes long, to the stream pointed to by stream, obtaining them from the location given by ptr.

So change the sequence and try again.

Upvotes: 0

Bechir
Bechir

Reputation: 1051

Your are writing all the content of buffer (100 char) in the receiving file. You need to write the exact amount of data read.

fwrite(buffer, 1, file_size, pFile)

Adding more checks for your code:

#include <stdio.h>
#include <stdlib.h>

#define BUFFER_SIZE   100

int main(void) {
    char buffer[BUFFER_SIZE]; 
    size_t file_size;
    size_t ret;

    FILE* rfile = fopen("input.txt","r+");
    if(rfile==NULL)
    {
      printf("couldn't open File \n");
      return 0;
    }

    fseek(rfile, 0, SEEK_END);
    file_size = ftell(rfile);
    fseek(rfile,0,SEEK_SET);

    printf("File size: %d\n",file_size);

    if(!file_size) {
        printf("Warring! Empty input file!\n");
    } else if( file_size >= BUFFER_SIZE ){
        printf("Warring! File size greater than %d. File will be truncated!\n", BUFFER_SIZE);
        file_size = BUFFER_SIZE;
    }

    ret = fread(buffer, sizeof(char), file_size, rfile);
    if(file_size != ret) {
        printf("I/O error\n");
    } else {
        FILE* pFile = fopen ( "newfile.txt" , "w+" );
        if(!pFile) {
            printf("Can not create the destination file\n");
        } else {
            ret = fwrite (buffer , 1 ,file_size , pFile );
            if(ret != file_size) {
                printf("Writing error!");
            }
            fclose (pFile);
        }
    }
    fclose(rfile);
    return 0;
}

Upvotes: 3

Prof. Falken
Prof. Falken

Reputation: 24937

You need to check the return values from all calls to fseek(), fread() and fwrite(), even fclose().

In your example, you have fread() read 1 block which is 100 bytes long. It's often a better idea to reverse the parameters, like this: ret = fread(buffer,1,file_size,rfile). The ret value will then show how many bytes it could read, instead of just saying it could not read a full block.

Upvotes: 2

luser droog
luser droog

Reputation: 19514

Note ftell returns a long, not a size_t. Shouldn't matter here, though. ftell itself is not necessarily a byte-offset, though. The standard requires it only to be an acceptable argument to fseek. You might get a better result from fgetpos, but it has the same portability issue from the lack of specification by the standard. (Confession: I didn't check the standard itself; got all this from the manpages.)

The more robust way to get a file-size is with fstat.

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd>

struct stat stat_buf;
if (fstat(filename, &buf) == -1)
    perror(filename), exit(EXIT_FAILURE);
file_size = statbuf.st_size;

Upvotes: 0

Related Questions