f



Copying a file to another file

Hi,

I wrote the following C program to copy a file to another file.

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

static FILE *open_file ( char *file, char *mode )
{
  FILE *fp = fopen ( file, mode );

  if ( fp == NULL ) {
    perror ( "Unable to open file" );
    exit ( EXIT_FAILURE );
  }

  return fp;
}

int main ( int argc, char *argv[] )
{
 /* int ch;*/
  FILE *from;
  FILE *to;
  char *buffer;
  long lSize;

  if ( argc != 3 ) {
    fprintf ( stderr, "Usage: %s <readfile1> <writefile2>\n", argv[0]
);
    exit (1);/* EXIT_FAILURE */
  }

  from = open_file ( argv[1], "r" );
  to= open_file ( argv[2], "w" );
  // obtain file size.
  fseek (from , 0 , SEEK_END);
  lSize = ftell (from);
  rewind (from);
  // allocate memory to contain the whole file.
  if (lSize > 256) {
    lSize = 256;
    buffer = (char*) malloc (lSize);
  } else {
    buffer = (char*) malloc (lSize);
  }
  if (buffer == NULL) exit (2);

  while((fread(buffer, 1, lSize, from)) != 0)
  {
   fwrite(buffer,1,lSize,to);
  }

  fclose ( from );
  fclose ( to );

  return 0;/*EXIT_SUCCESS*/
}


One thing to note about the program below is the no. of bytes that are
read and copied in each iteration of fread/fwrite. If the file size is
> 256 bytes, I limit the bytes read to 256 bytes and make it loop till EOF is reached. Unfortunately, this doesn't seem to work and we alway seem to write some more than the read data when the file size is > 256 bytes.

Can you help me figure out why this is not working as expected?

Thanks,
-Karthika
-- 
comp.lang.c.moderated - moderation address: clcm@plethora.net -- you must
have an appropriate newsgroups line in your header for your mail to be seen,
or the newsgroup name in square brackets in the subject line.  Sorry.
0
karthika
11/19/2005 1:03:06 PM
comp.lang.c.moderated 1019 articles. 1 followers. Post Follow

9 Replies
718 Views

Similar Articles

[PageSpeed] 23

On 19 Nov 2005 13:03:06 GMT, karthika.28@gmail.com wrote:

>Hi,
>
>I wrote the following C program to copy a file to another file.
>
>#include <stdio.h>
>#include <stdlib.h>
>
>static FILE *open_file ( char *file, char *mode )
>{
>  FILE *fp = fopen ( file, mode );
>
>  if ( fp == NULL ) {
>    perror ( "Unable to open file" );

It would be good to include the filename in this message so you know
which one is the problem.

>    exit ( EXIT_FAILURE );
>  }
>
>  return fp;
>}
>
>int main ( int argc, char *argv[] )
>{
> /* int ch;*/
>  FILE *from;
>  FILE *to;
>  char *buffer;
>  long lSize;
>
>  if ( argc != 3 ) {
>    fprintf ( stderr, "Usage: %s <readfile1> <writefile2>\n", argv[0]
>);
>    exit (1);/* EXIT_FAILURE */

EXIT_FAILURE need not be 1.

>  }
>
>  from = open_file ( argv[1], "r" );

Since you use fread later, you should open the file in binary mode,
not text.

>  to= open_file ( argv[2], "w" );
>  // obtain file size.
>  fseek (from , 0 , SEEK_END);
>  lSize = ftell (from);

This is not guaranteed to give you the value you expect.  Furthermore,
it is unnecessary.

>  rewind (from);
>  // allocate memory to contain the whole file.
>  if (lSize > 256) {
>    lSize = 256;
>    buffer = (char*) malloc (lSize);

This code is duplicated in both the if and the else and could be
placed in the common code that follows.

>  } else {
>    buffer = (char*) malloc (lSize);

Don't cast the return from malloc.  It hardly ever helps and can
prevent the compiler for issuing a diagnostic you would really want to
see.

>  }
>  if (buffer == NULL) exit (2);

2 may not be portable.

>
>  while((fread(buffer, 1, lSize, from)) != 0)

If the file is larger than 256 bytes, you read 256 at a time until the
last block.  At that time, you will read whatever portion is left. The
probability is better than 99.6% that this will be a short block but
you have not bothered to save the amount that was actually read. This
will cause the subsequent fwrite to send a full 256 to the output file
even if you only read 1 byte.

Try
	while ((lSize = fread(buffer, 1, lSize, from)) != 0)
so that the final fwrite sends the correct number of bytes.

>  {
>   fwrite(buffer,1,lSize,to);
>  }
>
>  fclose ( from );
>  fclose ( to );
>
>  return 0;/*EXIT_SUCCESS*/
>}
>
>
>One thing to note about the program below is the no. of bytes that are
>read and copied in each iteration of fread/fwrite. If the file size is
>> 256 bytes, I limit the bytes read to 256 bytes and make it loop till EOF is reached. Unfortunately, this doesn't seem to work and we alway seem to write some more than the read data when the file size is > 256 bytes.
>
>Can you help me figure out why this is not working as expected?


<<Remove the del for email>>
-- 
comp.lang.c.moderated - moderation address: clcm@plethora.net -- you must
have an appropriate newsgroups line in your header for your mail to be seen,
or the newsgroup name in square brackets in the subject line.  Sorry.
0
Barry
11/21/2005 10:40:19 PM
karthika.28@gmail.com wrote:
........
>     exit (1);/* EXIT_FAILURE */

exit(1) is not interchangable with exit(EXIT_FAILURE) -- if you want to 
portably exit with a failure code use the latter.

>   }
> 
>   from = open_file ( argv[1], "r" );
>   to= open_file ( argv[2], "w" );

Cut from here 8<------8<------8<

>   // obtain file size.
>   fseek (from , 0 , SEEK_END);
>   lSize = ftell (from);
>   rewind (from);
>   // allocate memory to contain the whole file.
>   if (lSize > 256) {
>     lSize = 256;
>     buffer = (char*) malloc (lSize);
>   } else {
>     buffer = (char*) malloc (lSize);
>   }

to here >8------>8------>8

and replace it with:

   lSize = 4096;
   buffer = malloc(lSize);

Transferring in larger blocks is usually faster, and on most platforms 
this won't use any more resources because memory is doled-out in 
4096-byte sized chunks anyway.

This will also allw your program to copy the content of file-like 
objects which rewind() cannot operate on -- you have no need to know the 
size of the source file.

Also note that it is bad practise to cast the return value of functions, 
as it hides bugs.  If your compiler doesn't like it when you remove the 
cast in front of malloc it's probably a C++ compilerand not a C compiler.

>   if (buffer == NULL) exit (2);

again, consider exit(EXIT_FAILURE) -- use perror to print what went wrong.

>   while((fread(buffer, 1, lSize, from)) != 0)

You need to store the return value of fread()...

>   {
>    fwrite(buffer,1,lSize,to);

.....and use it instead of lSize in the above line.  That'll fix the bug 
you've noticed.

>   }
> 
>   fclose ( from );
>   fclose ( to );

If you're going to tidy-up things that will be done for you at exit time 
anyway, you whould add a line to free your buffer.

> 
>   return 0;/*EXIT_SUCCESS*/
> }
-- 
comp.lang.c.moderated - moderation address: clcm@plethora.net -- you must
have an appropriate newsgroups line in your header for your mail to be seen,
or the newsgroup name in square brackets in the subject line.  Sorry.
0
WillerZ
11/21/2005 10:40:31 PM
karthika.28@gmail.com wrote:
[...]
>   while((fread(buffer, 1, lSize, from)) != 0)
>   {
>    fwrite(buffer,1,lSize,to);
>   }
[...]
> One thing to note about the program below is the no. of bytes that are
> read and copied in each iteration of fread/fwrite. If the file size is
> > 256 bytes, I limit the bytes read to 256 bytes and make it loop till EOF is reached. Unfortunately, this doesn't seem to work and we alway seem to write some more than the read data when the file size is > 256 bytes.
> 
> Can you help me figure out why this is not working as expected?

You will always write 256 bytes (lSize will be 256 if the filesize is >256),
even on the last chunk, when the fread() reads less than 256.  (Unless the
file is an exact multiple of 256.)

Use the return value of fread(), which will tell you how much was read,
as the length to pass to fwrite():

while(( len = fread(buffer, 1, lSize, from)) > 0)
   {
    fwrite(buffer,1,len,to);
   }

And, with this loop, there is no need to determine the filesize, as the
loop will copy everything anyway.  (Unless you want to make sure that
the total amount read is the same as the filesize.  However, I believe
that the standard does not guarantee that seeking to the end of a file
in binary mode returns the actual length of the file.)

-- 
+-------------------------+--------------------+-----------------------------+
| Kenneth J. Brody        | www.hvcomputer.com |                             |
| kenbrody/at\spamcop.net | www.fptech.com     | #include <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------------+
Don't e-mail me at: <mailto:ThisIsASpamTrap@gmail.com>
-- 
comp.lang.c.moderated - moderation address: clcm@plethora.net -- you must
have an appropriate newsgroups line in your header for your mail to be seen,
or the newsgroup name in square brackets in the subject line.  Sorry.
0
Kenneth
11/21/2005 10:40:36 PM
karthika.28@gmail.com wrote:
> Hi,
> 
> I wrote the following C program to copy a file to another file.
> 
> #include <stdio.h>
> #include <stdlib.h>
> 
> static FILE *open_file ( char *file, char *mode )
> {
>   FILE *fp = fopen ( file, mode );
> 
>   if ( fp == NULL ) {
>     perror ( "Unable to open file" );
>     exit ( EXIT_FAILURE );
>   }
> 
>   return fp;
> }
> 
> int main ( int argc, char *argv[] )
> {
>  /* int ch;*/
>   FILE *from;
>   FILE *to;
>   char *buffer;
>   long lSize;
> 
>   if ( argc != 3 ) {
>     fprintf ( stderr, "Usage: %s <readfile1> <writefile2>\n", argv[0]
> );
>     exit (1);/* EXIT_FAILURE */
>   }
> 
>   from = open_file ( argv[1], "r" );
>   to= open_file ( argv[2], "w" );
>   // obtain file size.
>   fseek (from , 0 , SEEK_END);
>   lSize = ftell (from);
>   rewind (from);
>   // allocate memory to contain the whole file.
>   if (lSize > 256) {
>     lSize = 256;
>     buffer = (char*) malloc (lSize);
>   } else {
>     buffer = (char*) malloc (lSize);
>   }
>   if (buffer == NULL) exit (2);

Assuming C99:

	size_t nbytes;
>   while((fread(buffer, 1, lSize, from)) != 0)

while ((nbytes = fread(buffer, 1, lSize, from)) != 0)

>   {
>    fwrite(buffer,1,lSize,to);

     fwrite(buffer, 1, nbytes, to);

Note that if the input is a terminal (say argv[1] was /dev/tty on a Unix 
platform), then you could get less than 256 bytes at a time - and you 
need to write out just those bytes that you read in.

>   }
> 
>   fclose ( from );
>   fclose ( to );
> 
>   return 0;/*EXIT_SUCCESS*/
> }
> 
> 
> One thing to note about the program below is the no. of bytes that are
> read and copied in each iteration of fread/fwrite. If the file size is
> 
>>256 bytes, I limit the bytes read to 256 bytes and make it loop till EOF is reached. Unfortunately, this doesn't seem to work and we alway seem to write some more than the read data when the file size is > 256 bytes.
> 
> 
> Can you help me figure out why this is not working as expected?
> 
> Thanks,
> -Karthika


-- 
Jonathan Leffler                   #include <disclaimer.h>
Email: jleffler@earthlink.net, jleffler@us.ibm.com
Guardian of DBD::Informix v2005.02 -- http://dbi.perl.org/
-- 
comp.lang.c.moderated - moderation address: clcm@plethora.net -- you must
have an appropriate newsgroups line in your header for your mail to be seen,
or the newsgroup name in square brackets in the subject line.  Sorry.
0
Jonathan
11/21/2005 10:40:43 PM
> <karthika.28@gmail.com> wrote
>
> I wrote the following C program to copy a file to another file.
>
> #include <stdio.h>
> #include <stdlib.h>
>
> static FILE *open_file ( char *file, char *mode )
> {
>  FILE *fp = fopen ( file, mode );
>
>  if ( fp == NULL ) {
>    perror ( "Unable to open file" );
>    exit ( EXIT_FAILURE );
>  }
>
>  return fp;
> }
>
> int main ( int argc, char *argv[] )
> {
> /* int ch;*/
>  FILE *from;
>  FILE *to;
>  char *buffer;
>  long lSize;
>
>  if ( argc != 3 ) {
>    fprintf ( stderr, "Usage: %s <readfile1> <writefile2>\n", argv[0]
> );
>    exit (1);/* EXIT_FAILURE */
>  }
>
>  from = open_file ( argv[1], "r" );
>  to= open_file ( argv[2], "w" );
>  // obtain file size.
>  fseek (from , 0 , SEEK_END);
>  lSize = ftell (from);
>  rewind (from);
>  // allocate memory to contain the whole file.
>  if (lSize > 256) {
>    lSize = 256;
>    buffer = (char*) malloc (lSize);
>  } else {
>    buffer = (char*) malloc (lSize);
>  }
>  if (buffer == NULL) exit (2);
>
>  while((fread(buffer, 1, lSize, from)) != 0)
>  {
>   fwrite(buffer,1,lSize,to);
>  }
>
>  fclose ( from );
>  fclose ( to );
>
>  return 0;/*EXIT_SUCCESS*/
> }
>
>
> One thing to note about the program below is the no. of bytes that are
> read and copied in each iteration of fread/fwrite. If the file size is
>> 256 bytes, I limit the bytes read to 256 bytes and make it loop till EOF 
>> is reached. Unfortunately, this doesn't seem to work and we alway seem to 
>> write some more than the read data when the file size is > 256 bytes.
>
> Can you help me figure out why this is not working as expected?

The last read may be fewer than 256 bytes, so the last write must be the 
same number of bytes.

Also, there's no point in trying to save memory by allocating a short buffer 
if the file is short. Even measuring the file is a complete waste of time. 
Just statically allocate a buffer of a reasonable fixed size.

And frankly, 256 bytes isn't reasonable, because even disk sectors are 
larger than that. I recommend something more like 16K.

-- 

Ciao,               Paul D. DeRocco
Paul                mailto:pderocco@ix.netcom.com 
-- 
comp.lang.c.moderated - moderation address: clcm@plethora.net -- you must
have an appropriate newsgroups line in your header for your mail to be seen,
or the newsgroup name in square brackets in the subject line.  Sorry.
0
Paul
11/21/2005 10:40:47 PM
karthika.28@gmail.com writes:

>   from = open_file ( argv[1], "r" );
>   to= open_file ( argv[2], "w" );
>   // obtain file size.
>   fseek (from , 0 , SEEK_END);
>   lSize = ftell (from);

ftell only reliably reports the size of the file if you opened it
in binary mode ("rb", and then you should also use "wb").

However, because your program limits the buffer to 256 bytes,
it doesn't actually need to check the size of the file beforehand.
It could just *always* allocate the same 256 bytes and loop
copying until it finds the end of the file.  On your computer,
it'd probably even be OK to allocate the buffer as an automatic
variable, rather than with malloc; this would further simplify
the program (and fix the memory leak).

>   while((fread(buffer, 1, lSize, from)) != 0)
>   {
>    fwrite(buffer,1,lSize,to);
>   }

Suppose the file is 260 bytes long, so lSize is 256.
The first fread call reads 256 bytes and returns 256.
The first fwrite call then writes those bytes back out.
The second fread call reads the remaining 4 bytes and returns 4.
But the second fwrite call again writes 256 bytes to the output file.
The third fread call returns 0, terminating the loop.

So, you should change the fwrite call so that it writes only as
much as was previously read.
-- 
comp.lang.c.moderated - moderation address: clcm@plethora.net -- you must
have an appropriate newsgroups line in your header for your mail to be seen,
or the newsgroup name in square brackets in the subject line.  Sorry.
0
Kalle
11/21/2005 10:41:01 PM
> Can you help me figure out why this is not working as expected?

Two problems:
(1) Use "rb" and "wb" fopen modes.  Otherwise stdio will map newlines
and ftell's idea of the file size won't match the apparent size when 
reading.
(2) You need to capture the number of bytes returned by fread and fwrite
just that many, not always lSize.
-- 
comp.lang.c.moderated - moderation address: clcm@plethora.net -- you must
have an appropriate newsgroups line in your header for your mail to be seen,
or the newsgroup name in square brackets in the subject line.  Sorry.
0
Douglas
11/21/2005 10:41:13 PM
On 19 Nov 2005 13:03:06 GMT, karthika.28@gmail.com wrote in
comp.lang.c.moderated:

You seem to have a misunderstanding about the meaning of the value
returned by the fread() function.

Let's suppose that the file you are copying has exactly 257 bytes.

> Hi,
> 
> I wrote the following C program to copy a file to another file.
> 
> #include <stdio.h>
> #include <stdlib.h>
> 
> static FILE *open_file ( char *file, char *mode )
> {
>   FILE *fp = fopen ( file, mode );
> 
>   if ( fp == NULL ) {
>     perror ( "Unable to open file" );
>     exit ( EXIT_FAILURE );
>   }
> 
>   return fp;
> }
> 
> int main ( int argc, char *argv[] )
> {
>  /* int ch;*/
>   FILE *from;
>   FILE *to;
>   char *buffer;
>   long lSize;
> 
>   if ( argc != 3 ) {
>     fprintf ( stderr, "Usage: %s <readfile1> <writefile2>\n", argv[0]
> );
>     exit (1);/* EXIT_FAILURE */
>   }
> 
>   from = open_file ( argv[1], "r" );
>   to= open_file ( argv[2], "w" );
>   // obtain file size.
>   fseek (from , 0 , SEEK_END);

Note that using the fseek() function on a file opened in text mode is
not necessarily well-defined.

>   lSize = ftell (from);
>   rewind (from);
>   // allocate memory to contain the whole file.
>   if (lSize > 256) {
>     lSize = 256;
>     buffer = (char*) malloc (lSize);

Don't cast the return value of malloc() and friends in C.  It is not
necessary and can hide the error of failing to include <stdlib.h>,
although you did not make that particular error in this case.

>   } else {
>     buffer = (char*) malloc (lSize);
>   }
>   if (buffer == NULL) exit (2);

OK, let's get down to the problem.  If the fseek/ftell on your source
file returned 257, you have set lSize to 256.  Now we'll look at your
loop:

>   while((fread(buffer, 1, lSize, from)) != 0)

The first time this loop control statement executes, it will read 256
bytes from the file into buffer.  Since you have asked it to read 256
elements each 1 byte in size, it will return 256, the number of
elements that it read.

But the second time it will read exactly one byte from the file into
your buffer.  And since you asked it to read elements of one byte
each, and it read one byte, it will return 1, the number of elements
that it read.

>   {
>    fwrite(buffer,1,lSize,to);

Here you are writing 256 bytes to the destination file, which is just
fine the first time, but not so good the second time.  There is only
one useful byte in the buffer, and the contents of the remaining 255
bytes are "indeterminate", which is standard-ese for "unspecified
garbage".

You need to examine the actual return value of fread() to tell you how
many bytes to write, not just look at whether or not it is non-zero.

>   }
> 
>   fclose ( from );
>   fclose ( to );
> 
>   return 0;/*EXIT_SUCCESS*/
> }
> 
> 
> One thing to note about the program below is the no. of bytes that are
> read and copied in each iteration of fread/fwrite. If the file size is
> > 256 bytes, I limit the bytes read to 256 bytes and make it loop till EOF is reached. Unfortunately, this doesn't seem to work and we alway seem to write some more than the read data when the file size is > 256 bytes.
> 
> Can you help me figure out why this is not working as expected?
> 
> Thanks,
> -Karthika

You need to define a variable to receive the value returned by fread()
and change your logic to something like this:

size_t how_many;

   while ((how_many = fread(buffer, 1, lSize, from) != 0)
   {
      /* write how_many bytes */
   }

-- 
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html
-- 
comp.lang.c.moderated - moderation address: clcm@plethora.net -- you must
have an appropriate newsgroups line in your header for your mail to be seen,
or the newsgroup name in square brackets in the subject line.  Sorry.
0
Jack
11/21/2005 10:41:22 PM
On 21 Nov 2005 22:40:19 GMT, Barry Schwarz <schwarzb@deloz.net> wrote:

> On 19 Nov 2005 13:03:06 GMT, karthika.28@gmail.com wrote:

> >  from = open_file ( argv[1], "r" );
> 
> Since you use fread later, you should open the file in binary mode,
> not text.
> 
Depending on platform, it might be a better idea to use binary mode
for a file-copy program, or not, or it might make no difference. But
it doesn't follow from using fread(). There are no barriers between
I/O "formats" in C. It is perfectly legal to use fread() on a text
stream, although it rarely useful.  And it is perfectly legal to use
fgets() on a binary file if it happens to contain newlines in suitable
places and no nulls (or you don't rely on the null to determine the
input length and instead pre-clear and reverse-scan, but that's much
more work than it's worth) or fscanf() it it contains data than can
usefully be matched against the sorts of things scanf format can
specify; these are relatively rare, but can happen.

- David.Thompson1 at worldnet.att.net
-- 
comp.lang.c.moderated - moderation address: clcm@plethora.net -- you must
have an appropriate newsgroups line in your header for your mail to be seen,
or the newsgroup name in square brackets in the subject line.  Sorry.
0
Dave
12/13/2005 12:45:18 PM
Reply:

Web resources about - Copying a file to another file - comp.lang.c.moderated

Copying - Wikipedia, the free encyclopedia
Copying is the duplication of information or an artifact based only on an instance of that information or artifact, and not using the process ...

Google Reportedly Copying Facebook’s Comment Plugin
The competition between Google and Facebook is about to spill over into plugins for websites: Reportedly launching soon, a comment system ties ...

Showing Apple employee #8 some of my artifacts. He remembers manually copying the Star Wars cassettes ...
jurvetson posted a photo: He has a rig that fed eight recoding tape drives from one master, and he would manually copy eight tapes at a time ...

Samsung Calls BS On Apple's Charges Of Copying - CONAN on TBS - YouTube
CONAN highlight: Samsung vigorously defends itself against Apple's absurd allegations! More CONAN @ http://teamcoco.com/video

CSAIL fixes software bugs automatically, in any language, by copying from safer applications
A new system can repair bugs in software using smart processing that imports functionality from other programs, all without access to source ...

Risk of other countries copying boat turn-backs low: UN High Commissioner for Refugees
The risk that other countries will copy Australia's hardline asylum seeker policies is low, the United Nations High Commissioner for Refugees ...

Hardware vendors sue Dutch government over copyright levies - regulation, legal, Dutch Home Copying Foundation ...
... on hard disks, smartphones, tablets and MP3 players that are meant to compensate the music and movie industries for losses caused by home copying. ...

Grace Jones slams Lady Gaga for copying her, describes her as soulless - The Courier-Mail Search Search ...
GRACE Jones has slammed Lady Gaga in a new interview, saying she didn’t “feel a soul” when she met the controversial pop star.

Iran claims to be copying US drone
CTV.ca Iran claims to be copying US drone Herald Sun AN IRANIAN military commander said the country is building a copy of a US spy drone captured ...

Hotel designer denies copying Aboriginal paintings
Guests at the Eclipse Hotel in Domaslaw, Poland, may be surprised to learn that its cutting-edge interior design is based on work by an Aboriginal ...

Resources last updated: 2/6/2016 10:19:01 PM