Unable to read file using fread in C - c

I am trying to read a file "file.raw" and 4 bytes at a time to an array and check if it has the particular 4 byte signature I am looking for. I am having trouble with this. The value of result I get is 0, instead of 4 when using fread.
#include<stdint.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef uint8_t BYTE;
int main(void)
{
size_t result;
FILE *inptr = fopen("file.raw","r+");
//Check if file can be opened.
if (inptr == NULL)
{
printf("File Open Error\n");
return -1;
}
long int x = 0;
while(!feof(inptr))
{
// Make space for reading in to an array
BYTE *array = (BYTE *) malloc(10);
if(array == NULL)
{
printf("Array Initialization Error\n");
return -1;
}
result = fread(array,1,4,inptr);
//Exit if file not read. ** This is where I can't get past.
if(result != 4)
{
printf("File Read Error\n");
printf("%d\n",result);
free(array);
fclose(inptr);
return -1;
}
//Compare strings
if(memcmp(array,"0xffd8ffe0",4)==0)
{
printf("File Start found\n");
printf("Exiting...\n");
printf("%p\n",inptr);
free(array);
fclose(inptr);
return 0;
}
x++;
free(array);
}
printf("%p\n",inptr);
printf("%ld\n",x);
fclose(inptr);
return 0;
}

My guess is that it doesn't fail on the first iteration of the while loop, but rather keeps reading the file until you reach end of the file, at which point fread() returns 0 and your program exits.
The reason it's not finding the signature is this:
memcmp(array,"0xffd8ffe0",4)==0
That memcmp() call is almost certainly not what you want (it's looking for the sequence of ASCII characters '0', 'x', 'f' and 'f').
PS As noted by #Mat in the comments, for maximum portability you should open the file in binary mode ("r+b" instead of "r+").

Try opening the file in binary mode ("r+b") instead of text mode ("r+"). You're probably being undone by unintentional CRLF conversions, messing up your binary data.

Related

Not encountering end of file (eof) in C

I am trying to run the code. All the images are coming fine as per specification excluding the last one.
The first four bytes (B) repeating are as follows :
b8 97 98 c5
The end of file is not encountered as a result the last image is found corrupted.
EDIT:
It is already mentioned that there are 50 images in the file.
You can get the raw file from : http://cdn.cs50.net/2017/fall/psets/4/recover/card.raw
The original code is as follows :
// Recovers lost images (.jpeg) in a memory card
#include <stdio.h>
#include <stdlib.h>
#define buffsize 10
// Function to check whether jpeg or not
int check_jpeg(unsigned char *argv) {
unsigned int v1 = (int)argv[0];
unsigned int v2 = (int)argv[1];
unsigned int v3 = (int)argv[2];
unsigned int v4 = (int)argv[3];
if (v1 == 0xff && v2 == 0xd8 && v3 == 0xff) {
switch (v4) {
case 0xe0:
case 0xe1:
case 0xe2:
case 0xe3:
case 0xe4:
case 0xe5:
case 0xe6:
case 0xe7:
case 0xe9:
case 0xea:
case 0xeb:
case 0xec:
case 0xed:
case 0xee:
case 0xef:
return 1;
break;
default:
return 0;
}
} else {
return 0;
}
}
int main(int argc, char *argv[]) {
// Cautioning the user for wrong usage
if (argc != 2) {
fprintf(stderr, "Usage: ./recover file\n");
return 1;
}
// Opens the .raw file to begin inspection
FILE *camera = fopen(argv[1], "r");
// Checks the validity of the opened file
if (camera == NULL) {
fprintf(stderr, "Error opening file: %s\n",argv[1]);
return 2;
}
int counter = 0; // Declaring and Initialising the counter
int online = 0; // To know whether image is being written
char *filename = (char*)malloc(buffsize);
FILE *outptr;
while (1) {
unsigned char *image = malloc(512);
if (image == NULL) {
fprintf(stderr, "Error creating pointer \n");
return 200;
}
fread(image, 512, 1, camera);
if (image != NULL) {
int flag = check_jpeg(image);
if (counter == 50) {
printf("%x %x %x %x\n", image[0], image[1], image[2], image[3]);
}
if (flag == 1) {
if (counter != 0) {
fclose(outptr);
}
counter++;
// Creating the output file pointer
snprintf(filename, buffsize - 1, "%03i.jpg", counter);
outptr = fopen(filename, "w");
if (outptr == NULL) {
fprintf(stderr, "Error opening file: %s\n", filename);
return 201;
}
// Writing to the file
fwrite(image, 512, 1, outptr);
online = 1;
} else
if (flag == 0 && online == 1) {
fwrite(image, 512, 1, outptr); // Continue writing to the output file
}
free(image);
} else {
fclose(camera);
fclose(outptr);
return 0;
}
}
}
There are multiple issues in your code:
you do not check how much data fread successfully reads. At end of file, fread returns 0, otherwise fread returns the number of blocks successfully read into the destination array. To keep track of bytes read, pass 1 as the block size and 512 as the number of blocks.
there is no real need to allocate the filename and the input/output buffers, local arrays are fine for your purpose.
the files should be open in binary mode: FILE *camera = fopen(argv[1], "rb");
the second argument to snprintf should be the buffer size, not the maximum number of characters to write: snprintf(filename, buffsize, "%03i.jpg", counter);
fread wont set the pointer (or is at least not guaranteed to) to NULL on failed read. In fact I think it is supposed to leave the pointer unchanged. fread will however return the number of bytes read, so you could change:
fread(image, 512, 1, camera);
if (image != NULL)
to
int bytesread=fread(image, 1, 512, camera);
if (bytesread!= 512)
You might be tempted to do the following:
while (!feof(camera)) {
However, this works only in the case of there being no other errors reading the file, and even then always results in there being one additional read of the file (the one that triggers the EOF condition). That last read may return bad or point to stale data and so needs to be handled as per #chqrlie's answer and this previous question about feof().
Bottom line:
Check the number of bytes read, if it less than requested then use ferror() and feof() to isolate the cause so you can respond accordingly.

Read binary file using struct to find records

I'm using the following code to read a binary file and use a struct to output the data. However, I know my data consist of only one record, and it seems to be printing out many records. I'm wondering why this might be?
FILE *p;
struct myStruct x;
p=fopen("myfile","rb");
//printf("Rcords of file:\n");
while(1)
{
fread(&x,sizeof(x),1,p);
if(feof(p)!=0)
break;
printf("\n\nID:%ld",x.ID);
}
fclose(p);
return 0;
The struct is fairly normal like this:
struct myStruct
{
int ID;
char name[100];
}
Use %d instead of %ld to print an int
And take a look to Why is “while ( !feof (file) )” always wrong?
A struct haves a fixed size, you can use ftell to get the size of the file and then divide using the size of the struct in order to get the number of records, also, always check the result of those functions.
Something like:
FILE *file;
long size;
size_t count, records;
file = fopen("myfile", "rb");
if (file == NULL) {
perror("fopen");
return 0;
}
if (fseek(file, 0, SEEK_END) == -1) {
perror("fseek");
return 0;
}
size = ftell(file);
if (size == -1) {
perror("ftell");
return 0;
}
if (fseek(file, 0, SEEK_SET) == -1) {
perror("fseek");
return 0;
}
records = size / sizeof(x);
for (count = 0; count < records; count++) {
if (fread(&x, sizeof(x), 1, file) == 1) {
printf("\n\nID:%d",x.ID); /* %d instead of %ld */
} else {
break;
}
}
But notice that you are always writing to the same variable on the stack.
EDIT:
How do you store the struct in the file?
I'm not storing it, a program is.
If it is not yours (you don't build the file using the same struct) then you can't know which is the sizeof(x) inside the file, read about structure padding and packing.
Use more protection. Test the result of functions.
FILE *p;
struct myStruct x;
p=fopen("myfile","rb");
assert(p); // Insure file opened
while(1) {
size_t n = fread(&x, sizeof(x), 1, p);
// feof() is insufficient,
// fread() can fail due to input errors too and not set end-of-file condition
// if(feof(p)!=0)
if (n == 0) {
break;
}
// printf("\n\nID:%ld",x.ID);
printf("\n\nID:%d", x.ID); // Use matching specifier
fflush(stdout); // Insure output occurs promptly
}
fclose(p);
return 0;
Since OP's code had a mis-matched printf specifier, it indicates that either warnings are not fully enabled or OP is using a weak compiler. Suggest fixing that to save time.

fwrite corrupts my text file

I have been tinkering around for days with a program for a class of mine, and I cannot get fwrite to cooperate. I've tried looking at the online resources for fread and fwrite, looked at my professor's examples, and tried time and time again to fix this, but nothing has worked. No matter what I do, fwrite makes it so that my text editor can't detect any kind of character encoding, so I'm presuming that fwrite is either writing memory addresses or garbage values to the file, making it so that I can't read it. The program is simply supposed to write the contents of one file into another.
Here is my code.
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[]) {
//initialize files
FILE* infile, *outfile;
char* buffer;
int read = 0;
//handle the case of having the wrong number of inputs.
if (argc != 4){
printf("Error: incorrect number of inputs\n");
//returning 1 will tell us that this was an error (as opposed to returning zero)
return 1;
}
else{
//handle the case of not having read acces to file 1
if ( access(argv[1], R_OK) == 1){
printf("Error: you do not have read access to the first file\n");
return 1;
}
else {
//handle the case of not having write access to file 2
if ( access(argv[2], W_OK) == 1){
printf("Error: you do not have write access to the second file\n");
return 1;
}
else{
//handle a bad buffer size (zero or negative number)
if ((int)*argv[3] < 0){
printf("Error: bad input for buffer size.\nBuffer size: %d \n", (int)*argv[3]);
return 1;
}
}
}
//open the files in the correct mode.
infile = fopen(argv[1], "r");
outfile = fopen(argv[2], "w");
buffer = malloc((int)*argv[3]);
while (!feof(infile)){
read = fread (buffer,1,(int)*argv[3],infile);
fwrite(buffer,1,(int)*argv[3],outfile);
}
}
//close files, and deallocate the buffer.
fclose(infile);
fclose(outfile);
free(buffer);
//if we made it here, then that means that our program ran correctly, so return zero.
return 0;
}
This is wrong
(int)*argv[3]
change it to
atoi(argv[3])
and it would be better if you store the value somewhere, and check that it's convertible to integer, something like
int size;
char *endptr;
size = strtol(argv[3], &endptr, 10);
if (*endptr != '\0')
errorNotAnIntegerAbortHere();
buffer = malloc(size);
.
.
.
not that, *argv[3] would be equivalent to argv[3][0] which is just the first character in argv[3].
fread will return less than the no. of requested bytes at EOF.
Change to
if (read)
fwrite(buffer,1,read,outfile);

Looking for a string of characters copied to a buffer

I have an assignment that has asked me to copy a file using buffered i/o. It has multiple requirements:
Take one parameter and an optional second
Open the first parameter for reading
Open the second for writing
If there is no second parameter make a new file called prog1.out
Use a buffer size of 20 bytes
When copying the file, print any buffer starting with the characters "rwxr"
close all opened files before exiting.
The problem I'm having is with number six, I've looked around and can't figure this out. I've tried memchr but I don't think I'm on the right track. If anyone can help push me in the right direction I'd be grateful.
This is my code:
# include <stdlib.h>
# include <stdio.h>
int main(int argc, char *argv[])
{
FILE *readfile, *writefile;
char buffer[1024];
int fileSize;
int readResult;
int writeResult;
// making sure arguments exist
if (argc < 2|| argc > 3){
printf("This program takes either 1 or 2 arguments.\n");
exit(1);
}
//Opening file for reading
readfile = fopen(argv[1], "r");
if (!readfile) {
printf("Unable to open file %s.\n", argv[1]);
exit(1);
}
//finding the file size
fseek (readfile, 0, SEEK_END);
fileSize = ftell (readfile);
fseek (readfile, 0, SEEK_SET);
// read the file
readResult = fread(buffer, 20, fileSize/20, readfile);
if (readResult == 0) {
printf("A read error occured.\n");
exit(1);
}
//check to see if there is a second parameter (argument)
if (argc == 3) {
writefile = fopen(argv[2], "w");
if (!writefile) {
printf("Unable to open file %s.\n", argv[2]);
exit(1);
}
writeResult = fwrite(buffer, 20, fileSize/20, writefile);
if (writeResult != readResult) {
printf("A write error occured.\n");
exit(1);
}
printf("File %s successfully copied to %s.\n", argv[1], argv[2]);
}
else {
writefile = fopen("program1.out", "w");
if (!writefile) {
printf("Unable to open file program1.out\n");
exit(1);
}
writeResult = fwrite(buffer, 20, fileSize/20, writefile);
if (writeResult != readResult) {
printf("A write error occured.\n");
exit(1);
}
printf("File %s successfully copied to %s.\n", argv[1], "program1.out
}
fclose(readfile);
fclose(writefile);
exit(0);
}
There's the naive way:
if(buffer[0] == 'r' && buffer[1] == 'w'
&& buffer[2] == 'x' && buffer[3] == 'r') {
//do something
}
But take a look at strncmp(), which you can use for comparing parts of a string.
remember to first check if you have read at least 4 chars into the buffer. e.g. if the file is 21 bytes long, your 2. fread might only read 1 character, and you shouldn't compare against the other 3 chars in the buffer.
If you print out the buffer with e.g. printf or puts or any other function that expects a string, the buffer needs to end with a '\0' byte, otherwise the string functions doesn't know when to stop.
I'll first answer the question you actually asked: memcmp is a good way to compare two buffers. Some caveats:
You also have to make sure the size of the buffer is at least as large as the size of the target string
memcmp returns 0 if the two buffers match, which can be counter-intuitive.
So for example, if you wanted to see if a buffer is equal to the string "rwxw", you could write
if (readresult >= strlen("rwxw") && !memcmp(buffer, "rwxw", strlen("rwxw"))) {
// buffer match occurred!
}
Personally I would use a "#define" or const char to ensure that the three places where that string appear are actually the same string. For example:
#define MATCH_STRING "rwxw"
if (readresult >= strlen(MATCH_STRING) && !memcmp(buffer, MATCH_STRING, strlen(MATCH_STRING))) {
// buffer match occurred!
}
However there are a couple of other problems with your code. One is that you need a loop that continually reads from the input file and write from the output file until the input is exhausted. For example, along the lines of
while (true) {
readResult = fread(buffer, 20, 1, readfile);
if (readResult == 0) {
// end of file
break;
}
// put your check for the "rwxr" string here!
writeResult = fwrite(buffer, readResult, 1, writefile);
if (writeResult != readREsult) {
printf("error\n");
}
}
Finally, you have what might be called a "stylistic" bug. There are two cases in your program: a specified filename and a default filename. Those two cases share a lot of code in common, but you did a cut and paste. This makes the code harder to understand, and more prone to bugs if it's changed in the future. If you are cutting-and-pasting code you're doing something wrong! Consider instead something like this, which maximizes shared code paths:
char *outFileName;
if (argc == 3) {
outFileName = argv[2];
} else {
outFileName = "prog1.out";
}
writefile = fopen(outFileName, "w");
if (!writefile) {
printf("Unable to open file %s.\n", writeFileName);
exit(1);
}

fwrite keeps failing not sure why

In my code below, the file is being written correctly as far as I can tell. When I look in the file floats.dat I see this stream of binary ÍÌL#33c#ÍÌÜ#ffFAßOeA^#^#bBf6zE33äCff<83>BÍ̦B
However my program always ends up triggering this if statement:
if(fread(inputFloats, sizeof(float), LENGTH, binaryFile) < LENGTH)
{
fprintf(stderr, "Problem reading some or all data from %s\n\n", binaryFileName);
return EXIT_FAILURE;
}
Does anybody see something I've done wrong here? Full code below.
#include <stdlib.h>
#include <stdio.h>
#define LENGTH 10
int main(void)
{
FILE *binaryFile, *textFile;
char *binaryFileName = "floats.dat", *textFileName = "floats.txt";
float floats[LENGTH] = {3.2, 3.55, 6.9, 12.4, 14.332, 56.5, 4003.4, 456.4, 65.7, 83.4};
float inputFloats[LENGTH];
int i;
if((binaryFile = fopen(binaryFileName, "r+")) == NULL)
{
fprintf(stderr, "Problem opening %s", binaryFileName);
}
if(fwrite(floats, sizeof(float), LENGTH, binaryFile) < LENGTH)
{
fprintf(stderr, "Problem writing some or all data to %s\n", binaryFileName);
return EXIT_FAILURE;
}
printf("DATA WRITTEN SUCCESSFULLY\n");
if(fread(inputFloats, sizeof(float), LENGTH, binaryFile) < LENGTH)
{
fprintf(stderr, "Problem reading some or all data from %s\n\n", binaryFileName);
return EXIT_FAILURE;
}
for(i = 0; i < LENGTH; i++)
{
printf("float[%d] = %f\n", i, floats[i]);
}
return EXIT_SUCCESS;
}
You're not working with text data so you should specify a binary mode when opening the file. Use r+b instead of r+
You need to fseek(binaryFile, 0, SEEK_SET) to "rewind" the file after writing. rewind can also be used for this case - fseek allows you to position the read/write pointer wherever you want.
The FILE structure keeps a record of where in the file it is currently pointing. Since you've just written to binaryFile, the file pointer is at the end of what you've written.
You therefore need to rewind the file, using fseek(binaryFile, 0, SEEK_SET); before you read.
You forgot to rewind your file before reading it:
rewind(binaryFile);
When you finish writing to the file, the FILE pointer is at the end of it, so of course if you try reading it will not work. Try using fseek to move the pointer to the beginning of the file before reading.
Please avoid this :
if((binaryFile = fopen(binaryFileName, "r+")) == NULL) {
and prefer this:
binaryFile = fopen(binaryFileName, "rb+");
if(!binaryFile) {

Resources