correct way to use fwrite and fread - c

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.

Related

Reading a pdf file with fread in C does not end up as expected

I am trying to read from a pdf file and write into another file where I run to the problem.
In the while loop, fread reads only 589 bytes which is expected to be 1024 for the first time.
In the second loop, fread reads 0 bytes.
I am sure that the pdf file is beyond 1024 bytes.
Here is a similar problem. The phenomenon is the same. But I do not use strlen() which causes that problem.
So how can I resolve the problem?
My code is here:
#include <stdio.h>
#define MAXLINE 1024
int main() {
FILE *fp;
int read_len;
char buf2[MAXLINE];
FILE *fp2;
fp2 = fopen("test.pdf", "w");
if ((fp = fopen("LearningSpark.pdf", "r")) == NULL) {
printf("Open file failed\n");
}
while ((read_len = fread(buf2, sizeof(char), MAXLINE, fp)) > 0) {
int write_length = fwrite(buf2, sizeof(char), read_len, fp2);
if (write_length < read_len) {
printf("File write failed\n");
break;
}
}
return 0;
}
fopen(filename, "r") is system dependent. See this post on what may happen to the data you read if you are on Windows, for example. Basically it is related to how certain characters are translated on different systems in text mode, ie., \n is "End-of-Line" on Unix-type systems, but on Windows it is \r\n.
Important: On Windows, ASCII char 27 will result in End-Of-File, if reading in text mode, "r", causing the fread() to terminate prematurely.
To read a binary file, use the "rb" specifier. Similarly for "w", as mentioned here, you should use "wb" to write binary data.
Binary files such as pdf files must be open in binary mode to prevent end of line translation and other text mode handling on legacy systems such as Windows.
Also note that you should abort when fopen() fails and you should close the files.
Here is a modified version:
#include <errno.h>
#include <stdio.h>
#include <string.h>
#define MAXLINE 1024
int main() {
char buf2[MAXLINE];
int read_len;
FILE *fp;
FILE *fp2;
if ((fp = fopen("LearningSpark.pdf", "rb")) == NULL) {
fprintf(stderr, "Open file failed for %s: %s\n", "LearningSpark.pdf", strerror(errno));
return 1;
}
if ((fp2 = fopen("test.pdf", "wb")) == NULL) {
fprintf(stderr, "Open file failed for %s: %s\n", "test.pdf", strerror(errno));
fclose(fp);
return 1;
}
while ((read_len = fread(buf2, 1, MAXLINE, fp)) > 0) {
int write_length = fwrite(buf2, 1, read_len, fp2);
if (write_length < read_len) {
fprintf(stderr, "File write failed: %s\n", strerror(errno));
break;
}
}
fclose(fp);
fclose(fp2);
return 0;
}

Storing .raw File Data as a Pointer Using C

I am attempting to read a '.raw' file which stores the contents of an image that was taken on a camera using C. I would like to store these contents into a uint16_t *.
In the following code I attempt to store this data into a pointer, using fread(), and then write this data into a test file, using fwrite(), to check if my data was correct.
However, when I write the file back it is completely black when I check it.
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#define MAX_ROW 2560
#define MAX_COL 2160
int main()
{
char filename[32] = "image1.raw";
FILE * image_raw = fopen(filename, "rb");
fseek(image_raw, 0, 2);
long filesize = ftell(image_raw);
/*READ IMAGE DATA*/
uint16_t * image_data_ptr;
image_data_ptr = (uint16_t *)malloc(sizeof(uint16_t)*MAX_ROW*MAX_COL);
fread(image_data_ptr, sizeof(uint16_t), filesize, image_raw);
fclose(image_raw);
/*TEST WRITING THE SAME DATA BACK INTO TEST RAW FILE*/
FILE *fp;
fp = fopen("TEST.raw", "w");
fwrite(image_data_ptr, sizeof(uint16_t), filesize, fp);
fclose(fp);
return 0;
}
There are multiple issues with your code:
lack of error handling.
not seeking the input file back to offset 0 after seeking it to get its size. Consider using stat() or equivalent to get the file size without having to seek the file at all.
not dividing filesize by sizeof(uint16_t) when reading from the input file, or writing to the output file. filesize is expressed in bytes, but fread/fwrite are expressed in number of items of a given size instead, and your items are not 1 byte in size.
not opening the output file in binary mode.
leaking the buffer you allocate.
With that said, try something more like this instead:
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
int main()
{
char filename[32] = "image1.raw";
FILE *image_raw = fopen(filename, "rb");
if (!image_raw) {
fprintf(stderr, "Can't open input file\n");
return -1;
}
if (fseek(image_raw, 0, SEEK_END) != 0) {
fprintf(stderr, "Can't seek input file\n");
fclose(image_raw);
return -1;
}
long filesize = ftell(image_raw);
if (filesize == -1L) {
fprintf(stderr, "Can't get input file size\n");
fclose(image_raw);
return -1;
}
rewind(image_raw);
long numSamples = filesize / sizeof(uint16_t);
/*READ IMAGE DATA*/
uint16_t *image_data_ptr = (uint16_t*) malloc(filesize);
if (!image_data_ptr) {
fprintf(stderr, "Can't allocate memory\n");
fclose(image_raw);
return -1;
}
size_t numRead = fread(image_data_ptr, sizeof(uint16_t), numSamples, image_raw);
if (numRead != numSamples) {
fprintf(stderr, "Can't read samples from file\n");
free(image_data_ptr);
fclose(image_raw);
return -1;
}
fclose(image_raw);
/*TEST WRITING THE SAME DATA BACK INTO TEST RAW FILE*/
FILE *fp = fopen("TEST.raw", "wb");
if (!fp) {
fprintf(stderr, "Can't open output file\n");
free(image_data_ptr);
return -1;
}
if (fwrite(image_data_ptr, sizeof(uint16_t), numSamples, fp) != numSamples) {
fprintf(stderr, "Can't write to output file\n");
fclose(fp);
free(image_data_ptr);
return -1;
}
fclose(fp);
free(image_data_ptr);
return 0;
}
You have already a great answer and useful comments
anyway, consider that if you want to iterate over your file, loaded in memory as a whole, as an array of unsigned words:
if the file size could be odd what to do at the last byte/word
you may read the file as a whole in a single call, after having the file size determined
fstat() is the normal way to get the file size
get the file name from the command line as an argument is much more flexible than recompile the program or change the file name in order to use the program
The code below does just that:
uses image.raw as a default for the file name, but allowing you to enter the file name on the command line
uses fstat() to get the file size
uses a single fread() call to read the entire file as a single record
A test using the original program file as input:
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 20/07/2021 17:40 1067 main.c
PS > gcc -Wall -o tst main.c
PS > ./tst main.c
File is "main.c". Size is 1067 bytes
File "main.c" loaded in memory.
PS > ./tst xys
File is "xys". Could not open: No such file or directory
The C example
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
int main(int argc, char**argv)
{
const char* default_file = "image.raw";
char f_name[256];
if (argc < 2)
strcpy(f_name, default_file);
else
strcpy(f_name, argv[1]);
FILE* F = fopen(f_name, "rb");
if (F == NULL)
{
printf("File is \"%s\". ", f_name);
perror("Could not open");
return -1;
}
struct stat info;
fstat(_fileno(F),&info);
printf("File is \"%s\". Size is %lu bytes\n", f_name, info.st_size);
uint16_t* image = malloc(info.st_size);
if (image == NULL)
{ perror("malloc() error");
return -2;
};
if (fread(image, info.st_size, 1, F) != 1)
{ perror("read error");
free(image);
return -3;
};
// use 'image'
printf("File \"%s\" loaded in memory.\n", f_name);
free(image);
fclose(F);
return 0;
}

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.

Break a file into chunks and send it as binary from client to server in C using winsock?

I created an application that send a text file from client to server
So far i'm send it as string like this:
fp = fopen(filename, "r");
if (fp != NULL) {
newLen = fread(source, sizeof(char), 5000, fp);
if (newLen == 0) {
fputs("Error reading file", stderr);
} else {
source[++newLen] = '\0'; /* Just to be safe. */
}
}else{
printf("The file %s does not exist :(");
return 1;
}
fclose(fp);
send(s , source , strlen(source) , 0); //send file
However my professor told me I must send the file in Binary and be ready to accept a file of any size
I'm trying to figure out how to send the file in binary and break it into chunks
You can copy it one byte at a time.
Reading/writing more than a byte at a time theoretically would make it read and write more efficiently to disk. But since the binary is likely short, and disk I/O is already internally buffered it probably doesn't make a noticeable difference.
perror() is a convenient function that displays the text associated with an error code returned from the most recent UNIX system call. The text in the quotes is the title it displays before showing you the system message associated with the code.
exit(EXIT_FAILURE) exits with a -1 value which is what scripts can test to see if your program succeeded or failed, as the exit status can be retrieved for a UNIX program.
size_t is an integer type, but it's named size_t to give a hint as to what you're using it for.
If you wanted to transfer more data at a time you could. But 1-byte xfers is simple and safe and it works.
FILE *exein, *exeout;
exein = fopen("filein.exe", "rb");
if (exein == NULL) {
/* handle error */
perror("file open for reading");
exit(EXIT_FAILURE);
}
exeout = fopen("fileout.exe", "wb");
if (exeout == NULL) {
/* handle error */
perror("file open for writing");
exit(EXIT_FAILURE);
}
size_t n, m;
unsigned char buff[8192];
do {
n = fread(buff, 1, sizeof buff, exein);
if (n)
m = fwrite(buff, 1, n, exeout);
else
m = 0;
} while ((n > 0) && (n == m));
if (m)
perror("copy");

Binary output in Windows

I wrote a program that reads a binary file, does some process with its contents and writes the results to a different file. In Linux it works perfectly, but in Windows it does not work; the output files are always 1KB...
This is a simplified version of the program:
#include <stdio.h>
void copyFile(char* source, char* dest);
int main (int argc, char* argv[])
{
if (argc != 3)
printf ("usage: %s <source> <destination>", argv[0]);
else
{
copyFile(argv[1], argv[2]);
}
}
void encryptFile(char* source, char* destination)
{
FILE *sourceFile;
FILE *destinationFile;
int fileSize;
sourceFile = fopen(source, "r");
destinationFile = fopen(destination, "w");
if (sourceFile == 0)
{
printf ("Could not open source file\n");
return;
}
if (destinationFile == 0)
{
printf ("Could not open destination file\n");
return;
}
// Get file size
fseek(sourceFile, 0, SEEK_END); // Seek to the end of the file
if (ftell(sourceFile) < 4)
return; // Return if the file is less than 4 bytes
fseek(sourceFile, 0, SEEK_SET); // Seek back to the beginning
fseek(sourceFile, 0, SEEK_SET); // Seek back to the beginning
int currentChar;
while ((currentChar = fgetc(sourceFile)) != EOF)
{
fputc(currentChar, destinationFile);
}
fclose(sourceFile);
fclose(destinationFile);
}
I would love to give you more details of the problem, but I don't have much experience programming C in Windows and I really don't know where may be the problem.
You should use the b flag to fopen:
fopen(source, "rb")
fopen(destination, "wb");
I understand that due to some (brain-damage) subjective decisions, on win32 reaching 0x1A on the input stream triggers an EOF if the file is not opened in "binary mode".
EDIT
In never looked into it but somebody is telling me now that 0x1A was used in DOS as a soft EOF.
Well, you're not opening the files in binary mode (use "wb" and "rb"). This doesn't matter on Linux, but it does on Windows, which will transform certain bytes when reading/writing a file in text mode. For example:
\r\n <--> \n
\x1a (Ctrl-Z) is treated as an EOF indicator
You need to use "rb" and "wb" with fopen.

Resources