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

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.

Related

fread and fwrite result file size are different

I am writing a program in Visual Studio.
I copied a file using fread and fwrite.
The output file size is bigger then input file.
Can you explain the reason?
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
int main()
{
char *buffer;
int fsize;
FILE *fp = fopen("test.txt", "r");
FILE *ofp = fopen("out.txt", "w");
fseek(fp, 0, SEEK_END);
fsize = ftell(fp);
buffer = (char *)malloc(fsize);
memset(buffer, 0, fsize); // buffer를 0으로 초기화
fseek(fp, 0, SEEK_SET);
fread(buffer, fsize, 1, fp);
fwrite(buffer, fsize, 1, ofp);
fclose(fp);
fclose(ofp);
free(buffer);
}
You open the files in text mode, which on the Windows operating system using Visual Studio involves non trivial translation phases, including end of line conversion. If your files have binary contents, such as executable, image and document files, end of line conversion replaces '\n' bytes with CR LF pairs, thereby increasing the output size.
You can avoid this issue by opening the files in binary mode with "rb" and "wb" mode strings.
Also note that a stream must be open in binary mode for ftell() to reliably return the file size, assuming the file supports seeking and is not larger than LONG_MAX which is only 2GB on Windows. Using stat to retrieve the file size from the OS is a better approach for POSIX systems. Copying the file one block at a time is also more reliable: it works for streams that do not support seeking and allows for copying files larger than available memory.
Here is a modified version with error checking:
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
const char *inputfile = "test.txt";
const char *outputfile = "out.txt";
FILE *fp = fopen(inputfile, "rb");
if (fp == NULL) {
fprintf(stderr, "cannot open %s: %s\n", inputfile, strerror(errno);
return 1;
}
FILE *ofp = fopen(outputfile, "wb");
if (ofp == NULL) {
fprintf(stderr, "cannot open %s: %s\n", outputfile, strerror(errno);
return 1;
}
if (fseek(fp, 0, SEEK_END)) {
fprintf(stderr, "%s: cannot seek to the end of file: %s\n",
inputfile, strerror(errno);
return 1;
}
size_t fsize = ftell(fp);
char *buffer = calloc(fsize, 1);
if (buffer == NULL) {
fprintf(stderr, "cannot allocate %zu bytes: %s\n",
fsize, strerror(errno);
return 1;
}
rewind(fp);
size_t nread = fread(buffer, fsize, 1, fp);
if (nread != fsize) {
fprintf(stderr, "%s: read %zu bytes, file size is %zu bytes\n".
inputfile, nread, fsize);
}
size_t nwritten = fwrite(buffer, nread, 1, ofp);
if (nwritten != nread) {
fprintf(stderr, "%s: wrote %zu bytes, write size is %zu bytes\n".
outputfile, nwritten, nread);
}
fclose(fp);
if (fclose(ofp)) {
fprintf(stderr, "%s: error closing file: %s\n".
outputfile, strerror(errno));
}
free(buffer);
return 0;
}

memcpy returns junk data when copying from character buffer

I'm attempting to read 4 bytes from the start of a character buffer, but I'm having an issue. memcpy is returning junk.
buffer contains the contents of the file. Using breakpoints I see that the file starts with 41 53 45 46 or ASEF in ASCII. This is the file signature for an Adobe Swatch File.
But when I copy those 4 bytes from a character buffer, to a 4 byte array signature, I get random data.
Any idea what I'm doing wrong here?
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
int main(int argc, char **argv)
{
errno_t err = NULL;
FILE *fptr = NULL;
long fileSize = 0;
unsigned char* buffer;
int i, bytesRead;
char signature[4] = { 0 };
err = fopen_s(&fptr, argv[1], "rb");
if (err || fptr == NULL) {
fprintf(stderr, "Could not open file: %s\n", argv[1]);
return 1;
}
// Get filesize
fseek(fptr, 0, SEEK_END);
fileSize = ftell(fptr);
rewind(fptr);
// Allocate memory to store file contents
buffer = malloc(fileSize);
if (buffer == NULL) {
fprintf(stderr, "Could not allocate %i bytes of memory\n", fileSize);
return 1;
}
// Read file contents into buffer
bytesRead = fread(buffer, 1, fileSize, fptr);
if (bytesRead == 0) {
fprintf(stderr, "Failed to read bytes from file: %s\n", argv[1]);
return 1;
}
// Read and check signature
memcpy(signature, &buffer, 4);
fclose(fptr);
return 0;
}
This line is wrong:
memcpy(signature, &buffer, 4);
You want to copy the data in your buffer, not the value of the buffer pointer itself. That means you want:
memcpy(signature, buffer, 4);

fread returns same number as nmemb yet end of file is reached

I am completing a problem in CS50, and my code is successful although I don't understand the behavior of a test inside of it.
Line 63 if (feof(inptr))checks if the end of file is reached, and then I ask to print the size of a buffer pointer which should be less than what it was initialized to (512).
It still returns a value of 512 although the EOF is reached, which doesn't make sense.
Could someone tell me what is wrong?
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
// ensure proper usage
if (argc != 2)
{
fprintf(stderr, "Usage: copy infile outfile\n");
return 1;
}
// remember filenames
char *infile = argv[1];
char *outfile = "000.jpg";
// open input file
FILE *inptr = fopen(infile, "r");
if (inptr == NULL)
{
fprintf(stderr, "Could not open %s.\n", infile);
return 2;
}
// open output file
FILE *outptr = fopen(outfile, "w");
if (outptr == NULL)
{
fclose(inptr);
fprintf(stderr, "Could not create %s.\n", outfile);
return 3;
}
// declaring variable
unsigned char buffer[512];
int count = 0;
int test = 512;
// Execute until we find end of card
while (!feof(inptr))
{
// Read buffer in card
fread(buffer, 1, sizeof(buffer), inptr);
// Checks for jpeg signature
if (buffer[0] == 0xff &&
buffer[1] == 0xd8 &&
buffer[2] == 0xff &&
(buffer[3] & 0xf0) == 0xe0)
{
fwrite(buffer, 1, sizeof(buffer), outptr);
fread(buffer, 1, sizeof(buffer), inptr);
// Checks if we are still in a jpeg, not the beginning of new one
while (buffer[0] != 0xff ||
buffer[1] != 0xd8 ||
buffer[2] != 0xff ||
(buffer[3] & 0xf0) != 0xe0)
{
// Exits loop if end of file
if (feof(inptr))
{
int size = sizeof(buffer);
printf("%i\n", size);
break;
}
fwrite(buffer, 1, sizeof(buffer), outptr);
fread(buffer, 1, sizeof(buffer), inptr);
}
if (feof(inptr))
{
break;
}
// Close jpeg
fclose(outptr);
// Change count to apply to next jpeg title
count++;
char img_num[4];
sprintf(img_num, "%03i.jpg", count);
// Assign new title to new jpeg
outfile = img_num;
printf("%s\n", outfile);
outptr = fopen(outfile, "w");
// We will have to read again in the main loop, so rewind
fseek(inptr, -512, SEEK_CUR);
}
}
printf("%i\n", test);
// close infile
fclose(inptr);
// close outfile
fclose(outptr);
// success
return 0;
}
sizeof(buffer) tells you how big buffer is. It does not tell you anything about what was in it—not how many bytes are currently valid, and not how many were read in the last fread.
The proper way to know how many bytes fread read is to use its return value. You ought to use code such as:
size_t BytesRead = fread(buffer, 1, sizeof(buffer), inptr);
If, after this statement, BytesRead is less than sizeof buffer, then fread did not read all the bytes you asked for. That is an indication that something is wrong, and it is a better indication than whether the file EOF flag is set.
(sizeof) returns size in bytes of the object representation of type
https://en.cppreference.com/w/cpp/language/sizeof
Since you allocated 512 bytes for buffer, sizeof will return 512. It doesn't matter what buffer is holding since its not a length check.

correct way to use fwrite and fread

I wrote a program
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *fp;
int r;
char arr[] = "this is the string";
char str[20] = {'\0'};
fp = fopen("fwrite.txt", "w");
fwrite(arr, 1, sizeof(arr), fp);
fseek(fp, SEEK_SET, 0);
r = fread(str, 1, sizeof(arr), fp);
if(r == sizeof(arr))
printf("read successfully\n");
else
{
printf("read unsuccessfull\n");
exit(1);
}
printf("read = %d\n", r);
printf("%s\n", str);
fclose(fp);
return 0;
}
I am trying to read in this way but I am not able to do it. What is the problem here, is it that I should put &str[i] and run a loop for fread or will fread be able to put data in the str?
I am getting junk and I don't understand why?
The primary problem is that you have the arguments to fseek() backwards — you need the offset (0) before the whence (SEEK_SET). A secondary problem is that you attempt to read from a file open only for writing. A more minor issue in this context, but one that is generally very important, is that you don't error check the fopen() call. (It is relatively unlikely that this fopen() will fail, but funnier things have been known.) You should also check the fwrite() call (you already check the fread(), of course).
Fixing all these might lead to:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int rc = EXIT_SUCCESS;
int r;
const char file[] = "fwrite.txt";
char arr[] = "this is the string";
char str[20] = {'\0'};
FILE *fp = fopen(file, "w+b");
if (fp == 0)
{
fprintf(stderr, "Failed to open file %s for reading and writing\n", file);
rc = EXIT_FAILURE;
}
else
{
if (fwrite(arr, 1, sizeof(arr), fp) != sizeof(arr))
{
fprintf(stderr, "Failed to write to file %s\n", file);
rc = EXIT_FAILURE;
}
else
{
fseek(fp, 0, SEEK_SET);
r = fread(str, 1, sizeof(arr), fp);
if (r == sizeof(arr))
{
printf("read successful\n");
printf("read = %d bytes\n", r);
printf("read data [%s]\n", str);
}
else
{
printf("read unsuccessful\n");
rc = EXIT_FAILURE;
}
}
fclose(fp);
}
return rc;
}
Example run:
$ ./fi37
read successful
read = 19 bytes
read data [this is the string]
$
Note that this works in part because you write the null byte at the end of the output string to the file, and then read that back in. The file isn't really a text file if it contains null bytes. The b in "w+b" mode isn't really needed on Unix systems where there's no distinction between a binary and a text file. If you're writing null bytes to a file on Windows, you should use the b to indicate binary mode.
If you chose to, you could reduce the 'bushiness' (or depth of nesting) by not having a single return in the main() function. You could use return EXIT_FAILURE; and avoid an else and another set of braces. The code shown is careful to close the file if it was opened. In a general-purpose function, that's important. In main(), it is less critical since the exiting process will flush and close open files anyway.
You can't read in a file with the "w" mode for fopen, use "w+" instead.
"r" - Opens a file for reading. The file must exist.
"w" - Creates an empty file for writing. If a file with the same name already
exists, its content is erased and the file is considered as a new empty file.
"a" - Appends to a file. Writing operations, append data at the end of the
file. The file is created if it does not exist.
"r+" - Opens a file to update both reading and writing. The file must exist.
"w+" - Creates an empty file for both reading and writing.
"a+" - Opens a file for reading and appending.

I/O with fread and fwrite

Below is my simple cat problem, which reads a file and print it on terminal. When I set the BUFISZE macro to 10, it works fine. If I set BUFSIZE to 100, it prints part of the file. If I set BUFIZE to 1024, it prints nothing. Could you anyone please explain what is going on?
#include <stdio.h>
#include <string.h>
#define BUFSIZE 10
int main(int argc, char **argv){
char buf[BUFSIZE];
FILE *fp;
if( (fp = fopen(*++argv, "r")) == NULL){
printf("cannot open %s\n", *argv);
return 1;
}
while( fread(buf, BUFSIZE, 1, fp) == 1 )
if (fwrite(buf,strlen(buf), 1, stdout) != 1 ){
printf("write error.\n");
return 2;
}
printf("\n");
return 0;
}
Don't use strlen here; you are not dealing with null-terminated strings here. You read fixed blocksizes. You should write the same amount of chars that you have read.
fread returns the number of elements of the given size that were successfully read. Use this information in your call to fread. For this to work, you must treat the data as BUFSIZE bytes, not as one block of BUFSIZE bytes. (If that sounds esoteric: Swap your second and third parameters in fread and fwrite. These functions cannot return a number greater than their third parameter, the element count.)
So:
char buf[BUFSIZE];
size_t n;
do {
n = fread(buf, 1, BUFSIZE, stdin);
if (n > 0) fwrite(buf, 1, n, stdout);
} while (n == BUFSIZE);

Resources