I'm currently working on a binary file creation. Here is what I have tried.
Example 1:
#include<stdio.h>
int main() {
/* Create the file */
int a = 5;
FILE *fp = fopen ("file.bin", "wb");
if (fp == NULL)
return -1;
fwrite (&a, sizeof (a), 1, fp);
fclose (fp);
}
return 0;
}
Example 2:
#include <stdio.h>
#include <string.h>
int main()
{
FILE *fp;
char str[256] = {'\0'};
strcpy(str, "3aae71a74243fb7a2bb9b594c9ea3ab4");
fp = fopen("file.bin", "wb");
if(fp == NULL)
return -1;
fwrite(str, sizeof str, 1, fp);
return 0;
}
Example 1 gives the right output in binary form. But Example 2 where I'm passing string doesn't give me right output. It writes the input string which I have given into the file and appends some data(binary form).
I don't understand and I'm unable to figure it out what mistake I'm doing.
The problem is that sizeof str is 256, that is, the entire size of the locally declared character array. However, the data you are storing in it does not require all 256 characters. The result is that the write operation writes all the characters of the string plus whatever garbage happened to be in the character array already. Try the following line as a fix:
fwrite(str, strlen(str), 1, fp);
C strings are null terminated, meaning that anything after the '\0' character must be ignored. If you read the file written by Example 2 into a str[256] and print it out using printf("%s", str), you would get the original string back with no extra characters, because null terminator would be read into the buffer as well, providing proper termination for the string.
The reason you get the extra "garbage" in the output is that fwrite does not interpret str[] array as a C string. It interprets it as a buffer of size 256. Text editors do not interpret null character as a terminator, so random characters from str get written to the file.
If you want the string written to the file to end at the last valid character, use strlen(str) for the size in the call of fwrite.
Related
I have written a basic code which writes into a file a string in binary mode (using fwrite()). Also I can read the same string from the file (using fread()) in to the buffer and print it. It works but in the part where I read from the file, extra junk is also read into the buffer. My question is how to know the length of the bytes to be read, correctly?
The following is the code --
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#define BUFSZ 81
char * get_string (char *, size_t);
int main (int argc, char * argv[])
{
if (argc != 2)
{
fprintf (stderr, "Invalid Arguments!!\n");
printf ("syntax: %s <filename>\n", argv[0]);
exit (1);
}
FILE * fp;
if ((fp = fopen(argv[1], "ab+")) == NULL)
{
fprintf (stderr, "Cannot openm file <%s>\n", argv[1]);
perror ("");
exit (2);
}
char string[BUFSZ];
char readString[BUFSZ];
size_t BYTES, BYTES_READ;
puts ("Enter a string: ");
get_string (string, BUFSZ);
// printf ("You have entered: %s\n", string);
BYTES = fwrite (string, sizeof (char), strlen (string), fp);
printf ("\nYou have written %zu bytes to file <%s>.\n", BYTES, argv[1]);
printf ("\nContents of the file <%s>:\n", argv[1]);
rewind (fp);
BYTES_READ = fread (readString, sizeof (char), BUFSZ, fp);
printf ("%s\n", readString);
printf ("\nYou have read %zu bytes from file <%s>.\n", BYTES_READ, argv[1]);
getchar ();
fclose (fp);
return 0;
}
char * get_string (char * str, size_t n)
{
char * ret_val = fgets (str, n, stdin);
char * find;
if (ret_val)
{
find = strchr (str, '\n');
if (find)
* find = '\0';
else
while (getchar () != '\n')
continue;
}
return ret_val;
}
in the part where I read from the file, extra junk is also read into the buffer.
No, it isn't. Since you're opening the file in append mode, it's possible that you're reading in extra data preceding the string you've written, but you are not reading anything past the end of what you wrote, because there isn't anything there to read. When the file is initially empty or absent, you can verify that by comparing the value of BYTES to the value of BYTES_READ.
What you are actually seeing is the effect of the read-back data not being null terminated. You did not write the terminator to the file, so you could not read it back. It might be reasonable to avoid writing the terminator, but in that case you must supply a new one when you read the data back in. For example,
readString[BYTES_READ] = '\0';
My question is how to know the length of the bytes to be read, correctly?
There are various possibilities. Among the prominent ones are
use fixed-length data
write the string length to the file, ahead of the string data.
Alternatively, in your particular case, when the file starts empty and you write only one string in it, there is also the possibility of capturing and working with how many bytes were read instead of knowing in advance how many should be read.
First of all you get string from the user, which will contain up to BUFSZ-1 characters (get_string() function will remove the trailing newline or skip any character exceeding the BUFSZ limit.
For example, the user might have inserted the word Hello\n, so that after get_string() call string array contains
-------------------
|H|e|l|l|o|'\0'|...
-------------------
Then you fwrite the string buffer to the output file, writing strlen (string) bytes. This doesn't include the string terminator '\0'.
In our example the contents of the output file is
--------------
|H|e|l|l|o|...
--------------
Finally you read back from the file. But since readString array is not initialized, the file contents will be followed by every junk character might be present in the uninitialized array.
For example, readString could have the following initial contents:
---------------------------------------------
|a|a|a|a|a|T|h|i|s| |i|s| |j|u|n|k|!|'\0'|...
---------------------------------------------
and after reading from the file
---------------------------------------------
|H|e|l|l|o|T|h|i|s| |i|s| |j|u|n|k|!|'\0'|...
---------------------------------------------
So that the following string would be printed
HelloThis is junk!
In order to avoid these issues, you have to make sure that a trailing terminator is present in the target buffer. So, just initialize the array in this way:
char readString[BUFSZ] = { 0 };
In this way at least a string terminator will be present in the target array.
Alternatively, memset it to 0 before every read:
memset (readString, 0, BUFSZ);
What is the difference between fread and fgets when reading in from a file?
I use the same fwrite statement, however when I use fgets to read in a .txt file it works as intended, but when I use fread() it does not.
I've switched from fgets/fputs to fread/fwrite when reading from and to a file. I've used fopen(rb/wb) to read in binary rather than standard characters. I understand that fread will get /0 Null bytes as well rather than just single lines.
//while (fgets(buff,1023,fpinput) != NULL) //read in from file
while (fread(buff, 1, 1023, fpinput) != 0) // read from file
I expect to read in from a file to a buffer, put the buffer in shared memory, and then have another process read from shared memory and write to a new file.
When I use fgets() it works as intended with .txt files, but when using fread it adds a single line from 300~ characters into the buffer with a new line. Can't for the life of me figure out why.
fgets will stop when encountering a newline. fread does not. So fgets is typically only useful for text files, while fread can be used for both text and binary files.
From the C11 standard:
7.21.7.2 The fgets function
The fgets function reads at most one less than the number of characters specified by n from the stream pointed to by stream into the array pointed to by s. No additional characters are read after a new-line character (which is retained) or after end-of-file. A null character is written immediately after the last character read into the array.
7.21.8.1 The fread function
The fread function reads, into the array pointed to by ptr, up to nmemb elements whose size is specified by size, from the stream pointed to by stream. For each object, size calls are made to the fgetc function and the results stored, in the order read, in an array of unsigned char exactly overlaying the object. The file position indicator for the stream (if defined) is advanced by the number of characters successfully read. If an error occurs, the resulting value of the file position indicator for the stream is indeterminate. If a partial element is read, its value is indeterminate.
This snippet maybe will make things clearer for you. It just copies a file in chunks.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char ** argv)
{
if(argc != 3) {
printf("Usage: ./a.out src dst\n");
printf("Copies file src to dst\n");
exit(EXIT_SUCCESS);
}
const size_t chunk_size = 1024;
FILE *in, *out;
if(! (in = fopen(argv[1], "rb"))) exit(EXIT_FAILURE);
if(! (out = fopen(argv[2], "wb"))) exit(EXIT_FAILURE);
char * buffer;
if(! (buffer = malloc(chunk_size))) exit(EXIT_FAILURE);
size_t bytes_read;
do {
// fread returns the number of successfully read elements
bytes_read = fread(buffer, 1, chunk_size, in);
/* Insert any modifications you may */
/* want to do here */
// write bytes_read bytes from buffer to output file
if(fwrite(buffer, 1, bytes_read, out) != bytes_read) exit(EXIT_FAILURE);
// When we read less than chunk_size we are either done or an error has
// occured. This error is not handled in this program.
} while(bytes_read == chunk_size);
free(buffer);
fclose(out);
fclose(in);
}
You mentioned in a comment below that you wanted to use this for byteswapping. Well, you can just use the following snippet. Just insert it where indicated in code above.
for(int i=0; i < bytes_read - bytes_read%2; i+=2) {
char tmp = buffer[i];
buffer[i] = buffer[i+1];
buffer[i+1] = tmp;
}
I am attempting to read a file into a character array, but when I try to pass in a value for MAXBYTES of 100 (the arguments are FUNCTION FILENAME MAXBYTES), the length of the string array is 7.
FILE * fin = fopen(argv[1], "r");
if (fin == NULL) {
printf("Error opening file \"%s\"\n", argv[1]);
return EXIT_SUCCESS;
}
int readSize;
//get file size
fseek(fin, 0L, SEEK_END);
int fileSize = ftell(fin);
fseek(fin, 0L, SEEK_SET);
if (argc < 3) {
readSize = fileSize;
} else {
readSize = atof(argv[2]);
}
char *p = malloc(fileSize);
fread(p, 1, readSize, fin);
int length = strlen(p);
filedump(p, length);
As you can see, the memory allocation for p is always equal to filesize. When I use fread, I am trying to read in the 100 bytes (readSize is set to 100 as it should be) and store them in p. However, strlen(p) results in 7 during if I pass in that argument. Am I using fread wrong, or is there something else going on?
Thanks
That is the limitation with attempting to read text with fread. There is nothing wrong with doing so, but you must know whether the file contains something other than ASCII characters (such as the nul-character) and you certainly cannot treat any part of the buffer as a string until you manually nul-terminate it at some point.
fread does not guarantee the buffer will contain a nul-terminating character at all -- and it doesn't guarantee that the first character read will not be the nul-character.
Again, there is nothing wrong with reading an entire file into an allocated buffer. That's quite common, you just cannot treat what you have read as a string. That is a further reason why there are character oriented, formatted, and line oriented input functions. (getchar, fgetc, fscanf, fgets and POSIX getline, to list a few). The formatted and line oriented functions guarantee a nul-terminated buffer, otherwise, you are on your own to account for what you have read, and insure you nul-terminate your buffer -- before treating it as a string.
I wrote a small program to get the magic number from an .au file and print it to console, but every time I try, instead of getting the intended .snd, I get .snd$ instead.
I'm not sure why this is happening, considering that I'm only reading in 4 bytes, which is what the magic number is comprised of. So, where is the extra character coming from?
#include <stdio.H>
int main()
{
FILE *fin;
int r;
char m[4], path[20];
scanf("%s", path);
fin = fopen(path, "r");
r = fread(&m, sizeof(char), 4, fin);
printf("magic number is %s\n", m);
return 0;
}
You're printing it as though it were a string, which in C, means that it's NUL-terminated. Change your code like this and it will work as you expect:
char m[5];
m[4] = '\0'; /* add terminating NUL */
Also, you should be aware that scanf is a dangerous function. Use a command line argument instead.
The problem is not how you are reading.
The problem is that your variable is only 4 chars length, and it needs a null character to indicate the end.
printf with %s will print the content of the variable until reach a null character, until that it can print garbage if your variable is not correctly ended.
To fix you can have a bigger variable and set the [4] char with null.
How the new code should look like:
#include <stdio.H>
int main()
{
FILE *fin;
int r;
char m[5], path[20];
scanf("%s", path);
/*Scanf can be dangerous because it can cause buffer overflow,
it means that you can fill your variable with more bytes than it supports, which can end up being used for buffer overflow attacks:
See more: http://en.wikipedia.org/wiki/Buffer_overflow */
fin = fopen(path, "r");
r = fread(&m, sizeof(char), 4, fin);
m[4] = '\0';
printf("magic number is %s\n", m);
return 0;
}
I am trying to read a file in C. But when I read, and write it to stdout it prints # also which there is no in my file. What is the reason?
#include <stdio.h>
int main() {
FILE *fp;
int br;
char buffer[10];
int i;
fp = fopen("a.txt","r");
while(1) {
br = fread(buffer,1,10,fp);
printf("%s",buffer);
if (br==0)
break;
}
}
Output:
1234567891#2345678912#3456789
12#3456789
12#
The file:
123456789123456789123456789
Your fread call reads up to 10 bytes correctly, but printf with %s requires string to be null terminated. You can fix it by increasing size of the buffer to be 11 bytes and after every call to fread write zero at the end of data, i.e. buffer[br] = 0;.
The other way to go is to tell printf what is the size of your data by calling printf("%.*s", br, buffer);. You don't need to modify your buffer array then.
Dynamically allocate your buffer and have it be initialized to zeros like this:
char *buffer = calloc(1, 11);
<do your read loop>
free(buffer)
This way you get the zero byte at the end which will terminate the string when printing it. When C prints a string it expects it to be terminated by a NULL (or 0) byte.