garbage when copying two files in C? - c

I have this copying code from infile to outfile,
the problem is that there is a lot of garbage added at the end of the outfile
ssize_t nread;
int bufsize=512;
char buffer[bufsize];
while ( (nread=read(infile, buffer, bufsize)>0))
{
if( write(outfile, buffer, bufsize)<nread )
{
close(outfile); close(infile); printf("error in write loop !\n\n");
return (-4);
}
}
if( nread == -1) {
printf ("error on last read\n"); return (-5);
}//error on last read /
what should i do to fix this ?

while ( (nread=read(infile, buffer, bufsize)>0))
should be:
while ( (nread=read(infile, buffer, bufsize)) >0 )
as > has higher precedence when compared to =.
Also
write(outfile, buffer, bufsize)
you are always writing bufsize number of bytes. But there need not be those many bytes read in the read operation. This could happen in the last iteration of the copying. To fix this you should be writing nread number of bytes.

Related

Copy data from file X to file Y program in C

I tried to write basic program in C which copy data from file to another with given source path, destination path and buffer size as input.
my problem is the destination file filled with junk or something because its way larger than the source (get bigger depending on buffer size) and can't be open.
How do i read and write just the bytes in the source?
i'm working in linux, and this is the actually copying part:
char buffer[buffer_size];
int readable=1;
int writeable;
while(readable != 0){
readable = read(sourcef, buffer, buffer_size);
if(readable == -1){
close(sourcef);
close(destf);
exit_with_usage("Could not read.");
}
writeable = write(destf, buffer, buffer_size);
if(writeable == -1){
close(sourcef);
close(destf);
exit_with_usage("Could not write.");
}
}
writeable = write(destf, buffer, buffer_size);
must be
writeable = write(destf, buffer, readable);
Currently you do not write the number of characters you read but all the buffer, so the output file is too large
You also manage wrongly the end of the input file
The return value of read is :
On success, the number of bytes read is returned (zero indicates end of file)
On error, -1 is returned
A proposal :
/* you already check input and output file was open with success */
char buffer[buffer_size];
for(;;){
ssize_t readable = read(sourcef, buffer, buffer_size);
if(readable <= 0){
close(sourcef);
close(destf);
if (readable != 0)
/* not EOF */
exit_with_usage("Could not read.");
/* EOF */
break;
}
if (write(destf, buffer, n) != n) {
close(sourcef);
close(destf);
exit_with_usage("Could not write.");
}
}
I suppose exit_with_usage calls exit() so does not return
Note in theory write may write less than the expected number of characters without being an error, and the write has to be done in a loop, but in that case it is useless to manage that
read function returns how many bytes were read to buffer(which has buffer_size). Its not always the case actual bytes read has same value as buffer size(consider scenario if there are not enough bytes left in source file to fully fill your buffer). So you should write to destination file not buffer_size(third argument of the write function), but how many bytes have you read - that is readable variable in your code
You should exit when readable returns an error.So
while(readable != 0){
should be
while(readable != -1){
So that loop could be terminataed when an readfile is exhausted.
You see currently after the whole readfile has been read, calling read fails but write is being called repeatedly since execution has no exit path for failure on read. Also write should only write the number of bytes read. So the code would look like this:
char buffer[buffer_size];
int readable=1;
int writeable;
while(readable != -1){
readable = read(sourcef, buffer, buffer_size);
if(readable == -1){
close(sourcef);
close(destf);
exit_with_usage("Could not read.");
}
writeable = write(destf, buffer, readable);
if(writeable == -1){
close(sourcef);
close(destf);
exit_with_usage("Could not write.");
}
}
Simple code
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> // For system calls write, read e close
#include <fcntl.h>
#define BUFFER_SIZE 4096
int main(int argc, char* argv[]) {
if (argc != 3) {
printf("Usage %s Src_file Dest_file\n", argv[0]);
exit(1);
}
unsigned char buffer[BUFFER_SIZE] = {0};
ssize_t ReadByte = 0;
int src_fd, dst_fd;
// open file in read mode
if ((src_fd = open(argv[1], O_RDONLY)) == -1) {
printf("Failed to open input file %s\n", argv[1]);
exit(1);
}
// open file in write mode and already exists to overwrite
if ((dst_fd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 644)) == -1) {
printf("Failed to create output file %s\n", argv[2]);
exit(1);
}
// loop
while (1) {
// read buffer
ReadByte = read(src_fd, buffer, sizeof(buffer));
// error with reading
if (ReadByte == -1) {
printf("Encountered an error\n");
break;
} else if (ReadByte == 0) {
// file end exit loop
printf("File copying successful.\n");
break;
}
// error with writing
if (write(dst_fd, buffer, ReadByte) == -1) {
printf("Failed to copying file\n");
break;
}
}
// Close file
close(src_fd);
close(dst_fd);
exit(0);
}
Run
./program src_file dest_file

Cannot Copy a Text File through fwrite and fread in C [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
Here is the Code:
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *f, *fp;
char buff[512];
int buff_size;
int bytes;
fp = fopen("File.txt", "rb");
if (fp == NULL) {
printf("Cannot Open Source File!\n");
exit(1);
}
f = fopen("append.txt", "ab+");
if (f == NULL) {
printf("Cannot Open Target File!\n");
fclose(fp);
exit(1);
}
buff_size = sizeof(buff);
while (bytes = fread(&buff, buff_size, 1, fp) > 0) {
if (bytes > 0)
fwrite(&buff, buff_size, 1, f);
else
break;
printf("Appending...\n\n");
}
rewind(f);
while (bytes = fread(&buff, buff_size, 1, f) > 0)
if (bytes > 0)
printf("%s", buff);
fclose(fp);
fclose(f);
}
So, it happens to be that this doesn't output anything and when I check the file "append.txt" it also does not contain anything.
Note that the Source File "File.txt" is not empty.
Can anyone tell me what is wrong with it?
EDIT:
I fixed the problem by replacing buff_size with strlen(buff) as this:
bytes = fread(&buff, strlen(buff), 1, f) > 0 and the same in fwrite() and second fread().
Can someone explain why this worked?
char buff[512];
int buff_size;
// [...]
bytes = fread(&buff, buff_size, 1, fp)
This will attempt to read one block of 512 bytes. The return value is the number of blocks read, so it won't be bytes. But leaving this aside, if your file is shorter than 512 bytes, this won't read anything.
What you want is read 512 times 1 byte, then you will get the byte count back, so swap places for buff_size and 1.
Side notes:
if you do your checks in the loop condition correctly like:
while ((bytes = fread(buff, 1, buff_size, fp)) > 0 )
the extra check for if (bytes > 0) is redundant.
when writing, you only want to write the amount of bytes you actually read:
fwrite(buff, 1, bytes, f);
For sizes, always use size_t -- int could very well be wrong:
size_t buff_size;
size_t bytes;
printing your buff with printf("%s", ) is undefined behavior because you don't add a '\0' byte after the data read by fread(). A C string must end with '\0'. When the data read by fread() doesn't contain a '\0' by accident, printf() will read and use uninitialized data and possibly even read beyond the bounds of your buff.
Felix Palmen listed a number of problems in your code, your fix is completely wrong as buff does not even have a null terminator.
Here is a better version:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
FILE *f, *fp;
char buff[512];
size_t bytes;
fp = fopen("File.txt", "rb");
if (fp == NULL) {
fprintf(stderr, "Cannot open source file!\n");
exit(1);
}
f = fopen("append.txt", "ab+");
if (f == NULL) {
fprintf(stderr, "Cannot open target file!\n");
fclose(fp);
exit(1);
}
while ((bytes = fread(buff, 1, sizeof buff, fp)) != 0) {
if (fwrite(buff, 1, bytes, 1, f) != bytes) {
fprintf(stderr, "Error writing to the target file\n");
break;
}
printf("Appending...\n\n");
}
rewind(f);
while ((bytes = fread(buff, 1, sizeof buff, f)) != 0) {
printf("%.*s", (int)bytes, buff);
}
fclose(fp);
fclose(f);
return 0;
}
bytes = fread(&buff, buff_size, 1, fp) > 0
Take a look at the C Precedence Chart. The operator > is above =, so the return value of fread will be compared to zero, and then the result of that comparison will be stored in bytes. You intended to write this
(bytes = fread(&buff, buff_size, 1, fp)) > 0
Here's my solution to your problem, given fixed file names. Were it my own code, it would take the file names as arguments.
#include <stdio.h>
int main(void)
{
const char src_file[] = "File.txt";
FILE *fp = fopen(src_file, "rb");
if (fp == NULL)
{
fprintf(stderr, "Cannot Open Source File '%s'!\n", src_file);
return(1);
}
const char tgt_file[] = "append.txt";
FILE *f = fopen(tgt_file, "ab+");
if (f == NULL)
{
fprintf(stderr, "Cannot Open Target File '%s'!\n", tgt_file);
fclose(fp);
return(1);
}
char buff[512];
int bytes;
while ((bytes = fread(buff, sizeof(char), sizeof(buff), fp)) > 0)
{
fwrite(buff, sizeof(char), bytes, f);
printf("Appending...\n\n");
}
rewind(f);
while ((bytes = fread(buff, sizeof(char), sizeof(buff), f)) > 0)
printf("%.*s", bytes, buff);
fclose(fp);
fclose(f);
return 0;
}
There are a variety of fixes, most of them articulated in comments somewhere along the line.
I made the file names into arrays so that the name could be used in both fopen() and in the error messages, which are printed to stderr, not stdout. This is helpful to other users in generalized code. If the file names come from command line arguments, it is trivial.
The calls to fread() were fixed so that the number of bytes is reported, rather than the number of 512-byte blocks (which will be 0 or 1). This involved reversing the order of the size/count arguments to fread(). The buffer was passed rather than the address of the buffer, too.
The number of bytes read was captured correctly.
The number of bytes read was used to control the size of the fwrite().
The number of bytes read was used to control the number of bytes printed by printf().
I don't like the special rule in C99 and later that allows main() — but only main() — to return 0 by default. AFAIAC, it's a function defined as returning an int; it should return an int. However, there are others who disagree.

How to minimize the number of system calls? in C

How to minimize the number of system calls read() and write() in my code ?
int copy(char* entry, char* exit){
char buf;
int in;
int out;
in = open(entry,O_RDONLY);
out = open(exit ,O_APPEND|O_WRONLY);
while(read(in, &buf, 1) != 0){
write(out, &buf, 1); }
close(in);
close(out);
return 0;
}
Assuming you enlarge your buffer to for example 256, now write:
char buf[256];
int n;
...
while((n=read(in, buf, sizeof(buf))) > 0){
write(out, buf, n);
}
This reads, upon every read, a maximum of 256 bytes. read returns the number of bytes read, so n now has this number, which is what you write out. The last read will be less than 256, so the last write will also be less than 256.

How to use read and write past BUFSIZ in C

For an assignment, I'm supposed to create two methods: Method one will read() and write() the input file to an empty output file, one byte at a time (slowly).
The other method will instead use char buf[BUFSIZ]; where BUFSIZ is from <stdio.h>. We are supposed to read() and write() with the BUFSIZ which will make things a lot faster.
The input file we test each method on is just a linux dictionary (/dict/linux.words).
I've correctly implemented method one, where I call read() and write() on one character at a time, copying the input file to the output file. Although it's very slow, it at least copies everything over.
My code for this looks like this:
// assume we have a valid, opened fd_in and fd_out file.
char buf;
while(read(fd_in, buf, 1) != 0)
write(fd_out, buf, 1);
For method two however, where I use BUFSIZ, I am not able to transfer every single entry into the output file. It fails in the z entries, and doesn't write anymore.
So, my first try:
// assume we have a valid, opened fd_in and fd_out file
char buf[BUFSIZ];
while(read(fd_in, buf, BUFSIZ) != 0)
write(fd_out, buf, BUFSIZ);
doesn't work.
I understand that read() will return either the number of bytes read or 0 if it is at the end of a file. The problem I'm having is understanding how I can compare read() to BUFSIZ, and then loop around and start read() at where it left off until I reach the real end of file.
Since your file will most likely not be an exact multiple of BUFSIZ you need to check for the actual number of bytes read, so that the last block will be written correctly, e.g.
char buf[BUFSIZ];
ssize_t n;
while((n = read(fd_in, buf, BUFSIZ)) > 0)
write(fd_out, buf, n);
this code:
// assume we have a valid, opened fd_in and fd_out file
char buf[BUFSIZ];
while(read(fd_in, buf, BUFSIZ) != 0)
write(fd_out, buf, BUFSIZ);
leaves much to be desired,
does not handle a short remaining char count at the end of the file,
does not handle errors, etc.
a much better code block would be:
// assume we have a valid, opened fd_in and fd_out file
char buf[BUFSIZ];
int readCount; // number of bytes read
int writeCount; // number of bytes written
while(1)
{
if( 0 > (readCount = read(fd_in, buf, BUFSIZ) ) )
{ // then, read failed
perror( "read failed" );
exit( EXIT_FAILURE );
}
// implied else, read successful
if( 0 == readCount )
{ // then assume end of file
break; // exit while loop
}
// implied else, readCount > 0
if( readCount != (writeCount = write( fd_out, buf, readCount ) ) )
{ // then, error occurred
perror( "write failed" );
exit( EXIT_FAILURE );
}
// implied else, write successful
} // end while
Note: I did not include the closing of input/output files statements
before each call to exit() however, that does need to be added

Strange behaviour of fgets

Ive got a function here that blocks on fgets but when I print something before fgets it doesn't block.
int exec_command(char *command, char *output_buf, int buf_size)
{
FILE* pipe = NULL;
char buffer[BUFFER_SIZE];
char tmp[SMALL_BUFFER_SIZE];
unsigned total_read = 0;
pipe = popen( command, "r");
if( !pipe )
{
//Error
return -1;
}
memset(buffer, 0, sizeof(buffer));
while( !feof(pipe) )
{
//printf("reading"); //If I uncomment this fgets doesnt block
if( fgets(tmp, sizeof(tmp), pipe) != NULL )
{
// check that it'll fit:
size_t len = strlen(tmp);
if (total_read + len >= sizeof(buffer))
break;
// and add it to the big buffer if it fits
strcat(buffer, tmp);
total_read += len;
}
}
//Is there anything to copy
if ( total_read )
strncpy (output_buf, buffer, buf_size);
return pclose(pipe);
}
Is there anything wrong on my function above?
Its because whatever is writing your pipe isn't flushing its out buffer. When you print, it ends up flushing that (not garenteed to happen though). When you don't print, the pipe isn't actually getting written to because its because stored in a kernel buffer until it fills, and then the kernel will write the data. Call fsync or flush on the pipe fd in the process that is writing to the pipe to make sure that the kernel buffer is flushed.
Add a new-line to the print-statement. It is (probably) line-buffered, and doesn't print until a new-line is encountered, you call fflush.

Resources