How to read particular data from file using fread? - c

Following code writes data of student into a file using fwrite and reads data using fread:
struct record
{
char name[20];
int roll;
float marks;
}student;
#include<stdio.h>
void main()
{
int i;
FILE *fp;
fp=fopen("1.txt","wb"); //opening file in wb to write into file
if(fp==NULL) //check if can be open
{
printf("\nERROR IN OPENING FILE");
exit(1);
}
for(i=0;i<2;i++)
{
printf("ENTER NAME, ROLL_ NO AND MARKS OF STUDENT\n");
scanf("%s %d %f",student.name,&student.roll,&student.marks);
fwrite(&student,sizeof(student),1,fp); //writing into file
}
fclose(fp);
fp=fopen("1.txt","rb"); //opening file in rb mode to read particular data
if(fp==NULL) //check if file can be open
{
printf("\nERROR IN OPENING FILE");
exit(1);
}
while(fread(&student.marks,sizeof(student.marks),1,fp)==1) //using return value of fread to repeat loop
printf("\nMARKS: %f",student.marks);
fclose(fp);
}
As you can see in output image, marks with some other values are also printed whereas for desired output marks only with with value 91 and 94 are required
Which corrections are needed to be done in the above code to get desired output?

You are reading and writing records of different lengths, and thus your reads are giving you empty floating point numbers. If you write your records as three segments of a structure, you must read back the entire length of the structure to locate the fields you are interested in.
while(fread(&student, sizeof(student), 1, fp) == 1)) //using return value of fread to repeat loop
printf("\nMARKS: %f",student.marks);

Doing fread operations of sizeof(student.marks) number of bytes at a time may give you spurious results, given how you did fwrite operations on sizeof(student) numbers of bytes.
Another way to think about this is to pretend you're a book publisher. You print or write a book onto one piece of paper at a time. When you want to go back and find the page number on each page, you wouldn't read the pages one word at a time. That will give you a weird/wrong answer. You read in the whole page to get back the page number you want.
Investigate fread-ing sizeof(student) number of bytes on each iteration, writing those bytes into a student struct. Then access the marks property of that struct.

Related

fread() not working correctly?

I have this code that is meant to read from a text file, store the information in a bin file and then read the information from the bin file and project it onto the screen.
I have the writing to the bin file all correct except when I go to print the tempStudents to the screen it always says the LAST option that is in the text file. So it's as if the only student it's saving is the last student.
#include<stdlib.h>
#include<stdio.h>
struct student {
char name[200];
float marks;
};
int main() {
FILE * txtFile;
struct student tempStudent;
// File pointer to binary file
FILE * binFile;
int searchNum;
if ((txtFile = fopen("/Users/Ash/Desktop/Lab 8B/input.txt", "r")) == NULL) {
printf("Can not open file input.txt\n");
}
else {
FILE * binFile;
binFile = fopen("/Users/Ash/Desktop/Lab 8B/binFile.bin","w+b");
while (fscanf(txtFile,"%s %f", tempStudent.name, &(tempStudent.marks)) == 2) {
fwrite(tempStudent.name,sizeof(char),sizeof(tempStudent.name),binFile);
fwrite(&tempStudent.marks,sizeof(int),1,binFile);
}
printf("Please enter the student you want to search for\n");
printf("For example if you want the first student type 1\n");
scanf("%d", &searchNum);
int i = 0;
for (i = 0; i <= searchNum; i++)
{
fread(tempStudent.name, 60, sizeof(char),binFile);
fread(&tempStudent.marks,60, sizeof(int),binFile);
}
// write code that reads in the student structure that the user asked for
// from the binary file and store it in the variable tempStudent
printf("The student name retreived is: %s\n", tempStudent.name);
printf("The student mark retreived is: %.2f\n", tempStudent.marks);
fclose(binFile);
fclose(txtFile);
}
return 0;
}
A file has something like a current position. After writing the binary data to the file this position is at the end. When you (try to) read the bin data in this state fread will read nothing.
Check the return values!
You are always searching one too far:
for (i = 0; i <= searchNum; i++)
if you want the first student (searchNum = 1), then you will in fact do two reads. Usually this gets you "one more than the value I intended to read".
More critically, if you are reading and writing from a file, you need to make sure you start at the right place. For this you have the fseek() function. Instead of doing lots of reads / writes, just make sure you are in the right place before reading or writing.
More importantly still, you seem to have variable length records for your name and marks - this makes the whole thing a giant mess. Some recommendations:
Make the record length constant - in this way you will be able to fseek to a particular record without having to read all the previous records first.
Be VERY CAREFUL about reading and writing to a file at the same time; consider first writing all the inputs to file, closing the file, then opening for reading
Make sure you read the right number of bytes... don't just hard wire "60".
Learn about fseek(). Google it.
You are writing 60*sizeof(int) bytes of data into a single float element:
struct student {
char name[200];
float marks;
};
struct student tempStudent;
fread(&tempStudent.marks,60,sizeof(int),binFile);
Surely you can't expect this code to work!!!

trouble reading a text file

I am trying to read a txt file with following contents:
test.txt
3,4
5,6
7,8
each pair is in one line. I want to put these values in an array. But I want the array size to adjust based on number of pairs in the test txt.
So I calculated the number of lines available in the txt file until EOF and assigned the number of lines to the array to assign the sizeof the array.Then when I try to read the file using fscanf I get some weird numbers which is not even part of this txt file like 2342,123123.
Here is my code:
#include <stdio.h>
int main(int argc , char **argv)
{
FILE *pf;
int k;
int counter=0;
int c;
pf = fopen("test.txt", "r");
if(pf==NULL)
{
printf("its nuull");
}
else
{
do
{
c=fgetc(pf);
if(c=='\n')
counter++;
}while(c!=EOF);
printf("counter value is = %d\n", counter);
int b[counter][2];
for(k=0;k<counter;k++)
{
fscanf(pf,"%d, %d" ,&b[k][0],&b[k][1]);
printf("%d,%d\n" ,b[k][0],b[k][1]);
}
}
fclose(pf);
}
I think you need to call:
rewind(pf);
after displaying your counter value.
This will reset the file pointer to the start of the file.
The issue is probably that the current file pointer is pointing at the end of the file. You need to read from the begining of the file now, so you need to do something like:
rewind(pf);
There are other mechanisms - for instance fseek or fsetpos, but rewind is what I would use here.
You might also check the return from fscanf - this will return the number of input items assigned. If this isn't 2 (in your case) then something went wrong.

trouble using fread in c

Im having some trouble figuring out how to properly format fread statements. The below code is just some randomn stuff Im practicing with. Basically it fills information into the first array (s), writes 's' to a file, and then reads the file into the second array (s2). However I can't seem to get the fread statement formated in a way that doesnt give an error or return garbage. The arrays are in char datatype because, if my understanding is correct, char uses less memory than other datatypes. The eventual application of this practice code is for a data compression project.
#include<stdio.h>
#include<string.h>
FILE *fp;
//file pointer
char s[56];
//first string
char s2[56];
//target string for the fread
int n=0;
//counting variable
int m=0;
int main (void)
{
fp=fopen("test.bin", "w+");
//open a file for reading and writing
strcpy(s, "101010001101010");
//input for the string
for(n=0;n<56;n++)
{
if(s[n]==1)
m=n;
else if(s[n]==0)
m=n;
}
printf("%d\n", m);
//the above for loop finds how many elements in 's' are filled with 1's and 0's
for(n=0;n<m;n++)
{
printf("%c", s[n]);
}
//for loop to print 's'
fwrite(s, m, 1, fp);
//writes 's' to the first file
s2=fread(&s2, m, 1, fp);
//an attempt to use fread...
printf("\n\ns2\n\n");
for(n=0;n<m;n++)
{
printf("%c", s2[n]);
}
printf("\n");
//for loop to print 's2'
fclose(fp);
printf("\n\n");
printf("press any number to close program\n");
scanf("%d", &m);
}
A FILE structure has an implicit seek position within the file. You read and write from that seek position. If you want to read what you have written, you need to change the seek position back to the beginning of the file with a call to fseek(). In fact, for a file open for reading and writing, you must call fseek() when switching between reading and writing.
The return value of the fread function is of type size_t. It is the number of elements successfully read. (reference: http://www.cplusplus.com/reference/cstdio/fread/)
Don't assign it to s2. Simply use fread(&s2, m, 1, fp);

Reading a File into an array of Structures in C

still really new to C but starting to get the hang of it....
My program is supposed to create/write a file and store information from an array of structures. That part is fine. What im having trouble with is reading from that file back into an empty array of structures....
here's my structs:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX 100
struct Video {
char name[1024]; //name
int ranking; // Number of viewer hits
char url[1024]; // YouTube URL
};
struct Video Collection[MAX];
here's my load method which reads from my file back into my array of structures:
void load()
{
FILE *fileName;
fileName = fopen("ranking.dbm", "rb");
if (fileName != NULL){
fread (Collection,1,1,fileName);
}
else {
printf("ERROR");
}
}
also here is my write method:
void save()
{
FILE * pFile;
pFile = fopen ( "Ranking.dbm" , "wb" );
fwrite (Collection, 1 , sizeof(Collection), pFile );
fclose (pFile);
}
however when i print out my array collection after loading.... its empty... even though i can see my file in the project folder and open it and verify that the data is in there....
am i correct in thinking that i dont need a buffer since i don't need to do any processing on it before using it?
also since i've already statically allocated space for memory.... am i correct in thinking that i can just read directly into the array?
here is my print code:
void printall()
{
int i;
printf("\nCollections: \n");
for(i = 0; i < tail; i++)
{
printf("\nVideo Name: %s", Collection[i].name);
printf("\nRanking (Hits): %d", Collection[i].ranking);
printf("\nURL: %s", Collection[i].url);
printf("\n");
}
}
fread is in fact designed to read arrays of structures from a file, but you have to use it correctly.
fread's four parameters are as follows:
void * ptr, size_t size, size_t count, FILE * stream
The first parameter is where to put the data (in your case, Collection). The second parameter is the size of each array element: in your case, you want to put sizeof(struct Video). The third parameter is the number of elements you want to read, in your case, MAX. The fourth parameter is the file to read from.
If you want to read into an array like struct Video Collection[MAX], you would then use fread(Collection, sizeof(struct Video), MAX, file). fread will return the total number of elements read, which will be ≤ MAX.
I'm seeing a few issues here.. first how you read the file:
fread (Collection,1,1,fileName);
This will read into collection 1 byte from fileName into Collection
You should check the return status of fread(), when it's successful it tells you the total number of bytes to be read. (parameter 2 * parameter 3, or 1*1 in your case).
When I modify your read code like this:
fread(Collection, sizeof(struct Video), 1, fileName);
It does successfully read from the file... however you have a different problem now. Let's say your file contained this:
something 5 http://something.com
nothing 3 http://nothing.com
So (I think) that's the format for your file, a name (ASCII), a ranking (int), and URL (ASCII). Now let's say your main() function looked like this:
int main ()
{
load();
printall();
return 0;
}
What you'd get back on stdout would be something like:
Collections:
Video Name: something 6 http://something.com
nothing 3 http://nothing.com
Ranking (Hits): 0
URL:
The reason is because you declared your array with static (and very large) elements. The fread() will try to read in the sizeof(struct Video) which is 1024+4+1024 bytes, so unless every one of your lines is the exact size (1024 chars for name and url) then you're going to get what looks like messed up or empty data.
I would suggest reading until you hit a space instead and storing each value in the correct element instead of trying to read out the full file into an array.
EDIT:
If you want to populate your array like:
fread(myarray, sizeofstruct, numberofstructs, file);
You have to guarantee the data length. In your example you'd have to say "name is however many characters, + blank spaces = 1024" and same for URL. That seems to be a horrible space waster. The better bet is to populate your array one element at a time:
for(0 to last_element){
set myarray.name = data until first space
set myarray.ranking = (int)data until second space
set myarray.url = data until newline
}
You can use fscanf() to read until a whitespace.
Frankly if you're going to populate one element at a time I'd just use character pointers for name and url and dynamically assign memory so you don't have huge wasted arrays.
First I have to assume you meant struct Video Collection[MAX];else your upper part is invalid C.
Second: you are reading 1 byte into Collection.
Try
fread(Collection, sizeof(struct Video), MAX, fileName);
This will read up to MAX times chunks of sizeof(struct Video)bytes into Collection.

read data from file

How to read the data from a file to a structure?
I have a structure like
struct data
{
char name[20];
int age;
};
In file student_info.txt I have
ravi 12 raghu 14 datta 13 sujay 10 rajesh 13
and so on with many other names with ages. How can I read this from file to the structure data?
Reading this name and age should be a loop i.e for the first time I will read 'ravi' and '12', then I should pack this data in the structure and will pass the structure to a function as soon as the structure is set. It should come back to the file and read 'raghu' and '14' again pack the structure with this data, and this should be in a loop till I read all the data from the file
Can anyone please tell how to implement the logic?
The approach is:
Create an instance of an array of your struct, a file pointer for file access, and a counter variable
Open the file stream using the file pointer - check that it has been successfully opened. The file pointer will point to NULL if fopen() has failed
Read the data into the struct array using a loop. fscanf() returns the number of successful 'matches' with its format string - here it will be 2 (use this for the loop condition)
Close the file
An example of the code:
#include <stdio.h>
#define FILENAME "student_info.txt"
#define MAX_NO_RECORDS 50
struct data
{
char name[20];
int age;
};
int main(void)
{
/* Declare an array of structs to hold information */
struct data StudentInfo[MAX_NO_RECORDS];
/* Declare a file pointer to access file */
FILE *s_info;
int student_no = 0; /* holds no. of student records loaded */
/* open the file for reading */
s_info = fopen(FILENAME, "r");
/* Check if an error has occured - exit if so */
if(s_info == NULL)
{
printf("File %s could not be found or opened - Exiting...\n", FILENAME);
return -1;
}
printf("Loading data...\n");
while(fscanf(s_info, "%19s %i", StudentInfo[student_no].name, &StudentInfo[student_no].age) == 2)
{
/* refer to records with index no. (0 to (1 - no. of records))
individual members of structure can be accessed with . operator */
printf("%i\t%-19s %3i\n", student_no, StudentInfo[student_no].name, StudentInfo[student_no].age);
student_no++;
}
/* after the loop, student_no holds no of records */
printf("Total no. of records = %i\n", student_no);
/* Close the file stream after you've finished with it */
fclose(s_info);
return 0;
}
You just need to read data from this file and split that string based on some criteria. as your file is not properly formatted it would be difficult for you to parse data.
In your current scenario your file contain only first name and a digit you can easily parse this by detecting a Space Character in your string. but this could lead a problem if any of your name contains a space.
First of all separate each pair of word by some character such as : or ; or a tab or line break.
then between each separated string split it by space and then read all content of file in a char array then from that array try to find that special character which indicates one record.
Separate each record in a different char array then for each generated array again and then split it based on space char and load in your struct
This is just for explanation, original implementation may be different,
Student std = {first string, second integer};
Hope that document solves your problem http://www.softwareprojects.com/resources//t-1636goto.html

Resources