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
Related
i am trying to create a record keeping random access file in C. As you know, in random access file, all the records are given a fixed standard byte length. so that they can be accessed randomly when needed using fseek() and fread() functions. Here i have kept that length as size of whole structure, which is 90 bytes. i have multiple character arrays in structure. when i get input from user in those arrays of characters using structure object, and pass that object to the fwrite function and i give size as size of structure, the character array data is written to the file. but because the text from user is mostly is less than 30 chracters mostly( max size of array), the fwrite function writes the string from user in file but also writes garbage values in file for those indexes which were not used in array. if i use fseek and fread() functions, the program reads data fine. but i want my file to be garbage values free and human readable. How can i do that?
`#include <stdio.h>
#define size 30
struct Record{
char account[size];
char name[size];
char address[size];
};
int main()
{
FILE *ptr = NULL;
ptr = fopen("testfile.txt", "w");
if (ptr == NULL)
{
printf("Could not open file.");
}
else
{
struct Record client;
char account[30];
char name[30];
char address[30];
printf("Enter account number: ");
gets(client.account);
printf("Enter name: ");
gets(client.name);
printf("Enter address: ");
gets(client.address);
fwrite(&client, sizeof(struct Record),1,ptr);
fclose(ptr);
ptr = fopen("testfile.txt", "r");
char buffer[size];
fseek(ptr,0,SEEK_SET);
fread(buffer,30,1,ptr);
puts(buffer);
fclose(ptr);
}
puts("Done!");
return 0;
}`
The data in file i am getting is of follwing form (input: 1 jack new york):
1 ((± 0(± /Œ¬¨þa òpv ± jack ‚Ž ((± 0(± 0(± ¤þnew york lþa à# €# 4(±
I think the problem above is due to the larger size given than length of strings. i also tried giving size as length of string. In that case, the garbage values were not printed. but in that case i will lose my principle of keeping each record of same length to have random access property in file. So how can i write my string data to file without writing garbage values and yet keep the length of each record same as standard lentgh we have decided.
I just recently found the solution to my problem. It was to place space characters ' ' after terminating character in the array. for example, if I have an array of size 30 and I have given it a string of only 10 characters, with the terminating character at the 11th position, I can store space in the remaining ones. so that when I write a whole string with size 30 in the file, the space characters are written and we do not get garbage values appearing in our file. instead, we will have our strings readable in the file.
I used this function for this purpose:
void spaces(char array[],int size)
{
int length = strlen(array);
for (int i = length + 1; i < size; i++)
{
array[i] = ' ';
}
}
I am currently trying to load a file into a struct consisting of 3 characters and 1 integer. The program should read from a data file and insert each line into an element of the struct. The first 3 properties being the first 3 characters of the line, then skipping the space and inserting the next characters(regardless of length) as an integer.
I was able to compile the program but it will not run. After some testing, I noticed that the program will not run with just the fscanf(). I'm not sure where to put the .dat file so I put it in the same folder as the exe.
An example of the data:
ABC 22
CDD 32
Here is my .c file:
void LoadGeneticCode(char *filename, codon c[]){
FILE *file = fopen(filename, "r");
int i = 0;
while(fscanf(file, " %c%c%c %d", &c[i].b1,&c[i].b2,&c[i].b3,&c[i].a) > 0){
printf("%s \n",c[i].b1);
i++;
}
fclose(file);
}
.h file:
typedef struct { char b1,b2,b3; int a;} codon;
void LoadGeneticCode(char *filename, codon c[64]);
%1s means one character, yes, but it also null-terminates the string. You're overwriting memory outside your intended buffer. %c is what you mean. You also don't need the temporary character variables, you can read directly into your structure fields.
Also scanf returns the number of fields successfully read, so your check has to be that it's >0 (or just equal to 4), not equal to 1.
I normally use R, and have a lot of trouble understanding C. I need to read and store a data file, shown below, so that I can perform calculations on the data. These calculations depend on user-entered infomation. Here's the data that I'm trying to read in (called "Downloads/exchange.dat" in my code),
dollar 1.00
yen 0.0078
franc 0.20
mark 0.68
pound 1.96
Here's where I'm at so far. This reads the first line of data only and also returns it, which is not what I want. I need to read this entire file, store the exchange rates with their respective currencies, and be able to perform calculations on them later.
I think I need a typedef, perhaps? Later in the program, I ask the user for information like "Convert from?" and "convert to?". In which case, they'll enter "mark", "yen", "dollar", etc. and I hope to match their response to the respective exchange rate (using the string.h library).
My code so far, to read in the data:
#include <stdio.h>
main(int argc, char *argv[])
{
FILE *fpt; // define a pointer to pre-defined structure type FILE
char c;
// open the data file for reading only
if ((fpt = fopen("Downloads/exchange.dat", "r")) == NULL)
printf("\nERROR - Cannot open the designated file\n");
else // read and display each character from the data file
do
putchar(c = getc(fpt));
while (c != '\n');
// close the data file
fclose(fpt);
}
I feel like I need something similar, but completely different to read and store entire data file. Your help is appreciated.
You'll need to create a data structure to hold them and then a vector of this struct which will hold each currency read. You should make use of the fscanf function that will not only save you from splitting values by hand but will also convert them for you. Here is something I came up with:
/* to store each currency you read */
struct currency {
char name[256];
double value;
};
int main(int argc, char ** argv) {
FILE * fp = fopen("x.dat", "r");
int count = 0, i;
struct currency currencies[30];
/* this will read at most 30 currencies, and stop in case a
* end of file is reached */
while (count < 30 && !feof(fp)) {
/* fscanf reads from fp and returns the amount of conversions it made */
i = fscanf(fp, "%s %lf\n", currencies[count].name, ¤cies[count].value);
/* we expect 2 conversions to happen, if anything differs
* this possibly means end of file. */
if (i == 2) {
/* for the fun, print the values */
printf("got %s %lf\n", currencies[count].name, currencies[count].value);
count++;
}
}
return 0;
}
To read them again, you'll need to iterate on the currencies array until you reach count iterations.
Since you already wants to match those values with the strcmp function, read the currency name, iterate on the array until you find a match and then perform calculations on those.
This is basic C knowledge and as much as I understand you're not used to using it, I strongly suggest you read a book to find these answers in them.
An example for writing:
FILE *fp;
fp=fopen("c:\\test.bin", "wb");
char x[10]="ABCDEFGHIJ";
fwrite(x, sizeof(x[0]), sizeof(x)/sizeof(x[0]), fp);
(write declaration)
size_t fwrite(const void *ptr, size_t size_of_elements, size_t number_of_elements, FILE *a_file);
If you were to read,
size_t fread(void *ptr, size_t size_of_elements, size_t number_of_elements, FILE *a_file);
I suggest you
define a struct like :
typedef struct{
char currency[10];
double rate;
}rate_currency;
getline:
in your main function you use getline to read the file line by line :
while ((read = getline(&line, &len, fpt)) != -1) ...
Separate:
use strchr to search for the space character to separate currency name from currency rate
Insert :
declare an array of your previous struct :
rate_currency arrOfStruct[10];
then, insert one by one
for example :
arrOfStruct[0].currency = "dollar"; //after you read it and separated it...
arrOfStruct[0].rate = 1.00;
You're Done!
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!!!
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.