C Programming: Read file and search in a second file based on the data found - c

I have two files, file1.txt and file2.txt:
file1.txt:
1234:James Smith:100:110
1111:Steve Jones:150:130
4321:Bob Wilson:110:140
file2.txt
100;Area 1;0.00
110;Area 2;3.00
120;Area 3;4.75
130;Area 4;5.95
140;Area 5;10.00
150;Area 6;12.00
What I would like to do is read file1.txt line by line and record some of the information to a file3.txt (output file) such as field 1 (number) and field 2 (name). To test that I could retrieve these, I used:
while (fscanf(file1, "%[^:]:%[^:]:%d:%d", number, name, &on, &off) == 4)
{
printf("Name contains: %s", name);
}
As expected, this retrieved all of the "name" (field 2) values and displayed them on screen.
I would now like to use the data stored in "on" and "off" to retrieve additional information from file2.txt. As you can see above, file1.txt fields 3 and 4 match up with field 1 in file2.txt. What I'm looking at getting in the final output file is:
1234 James Smith Area 1 to Area 2 3.00
1111 Steve Jones Area 6 to Area 4 6.05
4321 Bob Wilson Area 2 to Area 5 7.00
I'm not sure how to accomplish reading file1.txt line by line and performing the "check" with file2.txt at the same time and outputting. I also require a simple subtraction calculation in there as well.
Any help would be greatly appreciated. I don't have much experience with fscanf, fgets, reading files, etc.

This is an example of the struct definitions required-:
#define MAX_LINES 1000
struct rec1
{
int n;
char name[30];
int area1;
int area2;
};
struct rec1 rec1_list[MAX_LINES];
struct rec2
{
int area;
char desc[20];
int rating;
};
struct rec2 rec2_list[MAX_LINES];

Related

Print one number after the last word

while(!feof(fp)) {
printf("\n %s %s %s", post.name, post.lastnamn, post.clubb);
for(i = 1; i <= x; i++;)
{
printf(" %d", j.number[i]);
}
fread(&post, sizeof(postTyp), 1, fp);
}
I have created two typedef struct and I am referring to them with post and j.
I have created a program that asks for a users name, last-name and clubb and stores it in a text file. I have also created a program that creates x amount of numbers in the array number[i] and save it in a text file. x counts how many times you have run a program to create an name, last-name and clubb. So if you run the program 3 times 3 numbers will be created like example down below
So when i print it i get this
Hanna Svensson FCB 1 2 3
Fabian Svensson FCB 1 2 3
Patrik Svensson FCB 1 2 3
What i want is to print it like this
Hanna Svensson FCB 1
Fabian Svensson FCB 2
Patrik Svensson FCB 3
Any tips for how I may accomplish this?
The solution is to only use the outer loop and not the inner one
i=1;
while(!feof(fp))
{
printf("\n %s %s %s", post.name, post.lastnamn, post.clubb);
printf(" %d", j.number[i]);
i++;
/* ...*/
}
Note aside: your while loop construct is very quetionable.

Read and modify txt file (line by line)

So there was this light project in one of my past classes where the user would read a text file (lets call it "studentstuff.txt", see below)
*studentstuff.txt*
1
Bob Smith
24
3.5
2
Jill Williams
23
3.6
3
Tom Jones
32
2.4
4
Julie Jackson
21
3.1
5
Al Brown
23
3.35
6
Juan Garcia
22
3.4
-7
Melissa Davis
20
3.2
8
Jack Black
44
1.1
and the output would print out: 1) # of students 2) Average age 3) Average gpa. In this assignment we had a struct:
typedef struct{
int id;
char name[255];
int age;
float gpa;
}student;
According to the program, the "studentstuff.txt" will be read and sorted according to the struct and then after some little math and functions spits out the:
'#' of students:
Average age:
Average gpa:
The problem is I have the idea in my head, but I cant seem to put it into code. Could anyone help me out on this?
as with any programming problem the first action (after deciding the inputs and outputs) is the breaking down of the problem into simple discrete steps.
Such a set of steps for the OPs problem would look similar to:
open the input file
if any errors:
output user message to stderr
exit program, indicating error occurred
else
begin: loop:
input the info for one student
if any errors, except EOF:
output user message to stderr
cleanup by closing the input file
exit program, indicating an error occurred
else
update number of students
update total age
update total gpa
endif
goto top of loop
end loop:
endif
calculate the average age
calculate the average gpa
display number of students
display average student age
display average student gpa
cleanup by closing the input file
return to caller, indicating success
Because the calculations will produce fractions, to avoid problems, suggest the struct be defined as:
struct studentStruct
{
float id;
char name[255];
float age;
float gpa;
};
typedef struct studentStruct student;
Notice the separation of the struct definition from the typedef statement. It does not make any difference here, but will when working with a debugger (which needs the struct tag name to properly display all fields in the struct) and when working with large projects to help avoid confusion.

File Allocation Table logical structure

I’m trying to understand how FAT file systems work from a higher (more logical) level. A FAT file system has a file allocation table, with 1 entry for each available allocation unit (cluster) in the disk. This data structure is used to map a file with the address of the first cluster in which the file appears on the disk (a file almost certainly occupies more than 1 cluster, and these clusters are connected together in a linked-list style). So far so good. But what is the key in the file allocation table? Is the file name with full path?
For instance, let’s say that I need to access file C:\folder1\myFile.txt, the I/O manager searches the file name (including the path) in the file allocation table until it finds an entry, and if so, it returns the address of the first cluster. Is that how it works?
I read a lot of documentation online about this topic, but somehow the access to the file allocation table is still fuzzy for me. Thank you in advance for your help.
[EDIT]
The more I read on line, the more confused I am. I'm going to try with this simple example, hopefully it will clarify my question.
Let's say I have only 2 files in my C drive:
C:\myFile.txt
C:\folder1\myFile.txt
The file allocation table (in a very abstract way) would have 3 entries:
| Filename | Extension | First Cluster |
|----------|-----------|---------------|
1 | MYFILE | TXT | 150 |
2 | FOLDER1 | | 300 |
3 | MYFILE | TXT | 900 |
Assuming I'm correct so far, let's say that I want to access myFile.txt in C:\folder1: I cannot use the file name (MYFILE.TXT) itself as my key, because I have 2 entries with the same name (I wouldn't know which entry to pick).
At this point I guess I have to start from the folder, so I scan the FAT to find FOLDER1: I get entry #2 (cluster 300). What's next? How I would I keep scanning the table to find the directory entry that I need for "MYFILE.TXT", so that I can access the hard drive at specified cluster?
Maybe I'm looking at this from the wrong perspective, I don't know.
Thanks everyone for your help.
Take a look at this code, It is a somehow dir command which print all the names of directories and file in a root directory from disk D:\
#include<dos.h>
#include<stdio.h>
#include<iostream.h>
struct Boot {
char ignore1[11];
int Byte_Per_Sector;
char Serctors_Per_Cluster;
int Number_Of_Reserved_sectors;
char Number_of_FATS;
int Maximum_Number_of_root_dir;
int Total_Sector_count;
char Ignore2;
int Sectors_per_fat;
int Sectors_per_trach;
int Number_of_heads;
char ignore3[4];
char Total_sector_count_for_fat[4];
int ignore4;
char boot_signature;
char Volume_id[4];
char Volume_lable[11];
char File_system_type[8];
char Rest_of_boot_sector[450];
};
struct FCB {
char file_name[8];
char extension[3];
char attribute;
int reserved;
int creation_time;
int creation_date;
int last_access_date;
int ignore_in_fat;
int last_write_time;
int last_write_date;
int first_logic_cluster;
char file_size[4];
};
void main(){
FCB root[16]; //to read all the Root directory
if(absread(3,1,217,&root) ==0) { // start read from disk number 3 , 1 sector and the first sector number is 217 (from the hard disk)
cout<<"Read of Root Directory started:"<<endl;
for(int j=1;j<15;j++){
if(root[j].file_name[0]==0x00){//0x00 represents Unused file
break;
}
if(root[j].attribute!=0x0F) //0x0f mean this directory entry is part of a long file name
if(root[j].file_name[0]!='?')
for(int i=0;i<7;i++){
printf("%c",root[j].file_name[i]); // print the name of all files and directories
}
cout<<endl<<root[j].first_logic_cluster; to locate where is the first cluster contains the data on HD
cout<<endl;
}
cout<<"end of dirs in this cluster"<<endl;
}
else {
cout<<"error"<<endl;
}
cout<<"===================="<<endl;
char buffer[512];
//here to read what a file contains after calculating the physical address of that file
if(absread(3,1,283,&buffer) ==0) {
for(int i=0;i<512;i++ ){
cout<<buffer[i];
}
}
}
Things to notice
1-The first struct is the most important thing in FAT because allinformation is stored here
2- FCB contains information about files and directories in root directory
3- This code can be run on Windows 3.11 and (Turbo c++) is the program to code and compile
4- the code represent FAT12 and Integer is 2 bytes
If you have any questions i hope i can help you

C: How to properly output struct from .txt file?

First time I have asked a question here. First here's the code:
void displayCompanyInfo(STAFF e[], int *s)
{
FILE *payRoll;
int i = 0;
int rosterNumber [100];
int count = 1;
if ((payRoll = fopen("payRoll.txt", "r")) == NULL)
{
perror ("error");
exit (0);
}
cls;
while (fgets(e[i].name, sizeof(e[i].name), payRoll) != NULL)
{
printf ("Record %i: ", count++);
printf("%s\n", e[i].name);
}
fclose(payRoll);
printf("\n\n");
pause;
cls;
} // end of display
Basically this code works. However when the text file displays it reads like this:
Record 1: Name: blah
Record 2: Age: 23
Record 3: Hourly Rate: 34
Instead I want it to read it as follows:
Record 1: Name: Blah
Age: 23
Hourly Rate: 34
Record 2: Name: Blah2
Age: 24
Hourly Rate: 35
And so on...
Any idea on how I can get this to work. I didn't post whole program because I didn't want to over do my thread. But if you need it let me know.
To this case you have to work with binary file handling.With text file it is not possible.
You have to read,write chunk of data in terms of bytes and handle it accordingly to retrieve you structure.
Say
struct e{
char name[20],
int age,
int hourly_rate
};
This structure will require
20(name) + 4(age) + 4(hourly_rate) bytes.Then you should write 28 bytes at a time in binary file and retrieve 28 bytes accordingly,which is not possible in case of text file.Because text file considers every thing as character,say age=23 it considers age field as 2 bytes and if age=3,it consider it as 1 byte.But binary file considers both thing as 4 bytes which is actual size of integer.
So the solution to your problem is binary file handling.
The problem is that the loop considers each line as a record. Instead, a record should be 3 lines. So read 3 things in the loop - add the 2 missing right before the printf.

C Primer 5th - Task 14-6

A text file holds information about a softball team. Each line has data arranged as follows:
4 Jessie Joybat 5 2 1 1
The first item is the player's number, conveniently in the range 0–18. The second item is the player's first name, and the third is the player's last name. Each name is a single word. The next item is the player's official times at bat, followed by the number of hits, walks, and runs batted in (RBIs). The file may contain data for more than one game, so the same player may have more than one line of data, and there may be data for other players between those lines. Write a program that stores the data into an array of structures. The structure should have members to represent the first and last names, the at bats, hits, walks, and RBIs (runs batted in), and the batting average (to be calculated later). You can use the player number as an array index. The program should read to end-of-file, and it should keep cumulative totals for each player.
The world of baseball statistics is an involved one. For example, a walk or reaching base on an error doesn't count as an at-bat but could possibly produce an RBI. But all this program has to do is read and process the data file, as described next, without worrying about how realistic the data is.
The simplest way for the program to proceed is to initialize the structure contents to zeros, read the file data into temporary variables, and then add them to the contents of the corresponding structure. After the program has finished reading the file, it should then calculate the batting average for each player and store it in the corresponding structure member. The batting average is calculated by dividing the cumulative number of hits for a player by the cumulative number of at-bats; it should be a floating-point calculation. The program should then display the cumulative data for each player along with a line showing the combined statistics for the entire team.
team.txt (text file I'm working with):
4 Jessie Joybat 5 2 1 1
4 Jessie Joybat 7 3 5 3
7 Jack Donner 6 3 1 2
11 Martin Garder 4 3 2 1
15 Jaime Curtis 7 4 1 2
2 Curtis Michel 3 2 2 3
9 Gillan Morthim 9 6 6 7
12 Brett Tyler 8 7 4 3
8 Hans Gunner 7 7 2 3
14 Jessie James 11 2 3 4
12 Brett Tyler 4 3 1 3
Since I'm a beginner in C, either I misinterpreted the task from what was asked originally or it's unfairly complex (I believe the former is the case). I'm so lost that I can't think of the way how could I fill in by the criteria of index (player number) every piece of data, keep track of whether he has more than one game, calculate and fetch bat average and then print.
What I have so far is:
#define LGT 30
struct profile {
int pl_num;
char name[LGT];
char lname[LGT];
int atbat[LGT/3];
int hits[LGT/3];
int walks[LGT/3];
int runs[LGT/3];
float batavg;
};
//It's wrong obviously but it's a starting point
int main(void)
{
FILE *flx;
int i,jc,flow=0;
struct profile stat[LGT]={{0}};
if((flx=fopen("team.txt","r"))==NULL) {
fprintf(stderr,"Can't read file team!\n");
exit(1);
}
for( jc = 0; jc < 11; jc++) {
fscanf(flx,"%d",&i);
stat[i].pl_num=i;
fscanf(flx,"%s",&stat[i].name);
fscanf(flx,"%s",&stat[i].lname);
fscanf(flx,"%d",&stat[i].atbat[flow]);
fscanf(flx,"%d",&stat[i].hits[flow]);
fscanf(flx,"%d",&stat[i].walks[flow]);
fscanf(flx,"%d",&stat[i].runs[flow]);
flow++;
}
}
Advice 1: don't declare arrays like atbat[LGT/3].
Advice 2: Instead of multiple fscanf you could read the whole line in a shot.
Advice 3: Since the number of players is limited and the player number has a good range (0-18), using that player number as an index into the struct array is a good idea.
Advice 4: Since you need cumulative data for each player (no need to store his history points), then you don't need arrays of integers, just an integer to represent the total.
So:
#include <stdio.h>
#define PLAYERS_NO 19
typedef struct
{
char name[20+1];
char lastName[25+1];
int atbat;
int hits;
int walks;
int runs;
float batavg;
} Profile;
int main(int argc, char** argv)
{
Profile stats[PLAYERS_NO];
int i;
FILE* dataFile;
int playerNo;
Profile tmpProfile;
int games = 0;
for(i=0; i<PLAYERS_NO; ++i)
{
stats[i].name[0] = '\0';
stats[i].lastName[0] = '\0';
stats[i].atbat = 0;
stats[i].hits = 0;
stats[i].walks = 0;
stats[i].runs = 0;
}
dataFile = fopen("team.txt", "r");
if ( dataFile == NULL )
{
fprintf(stderr, "Can't read file team!\n");
exit(1);
}
for(i=0; i<PLAYERS_NO && !feof(dataFile); ++i, ++games)
{
fscanf(dataFile, "%d", &playerNo);
if ( playerNo <0 || playerNo > PLAYERS_NO )
{
fprintf(stderr, "Player number out of range\n");
continue;
}
fscanf(dataFile, "%s %s %d %d %d %d",
&tmpProfile.name,
&tmpProfile.lastName,
&tmpProfile.atbat,
&tmpProfile.hits,
&tmpProfile.walks,
&tmpProfile.runs);
printf("READ: %d %s %s %d %d %d %d\n",
playerNo,
tmpProfile.name,
tmpProfile.lastName,
tmpProfile.atbat,
tmpProfile.hits,
tmpProfile.walks,
tmpProfile.runs);
strcpy(stats[playerNo].name, tmpProfile.name);
strcpy(stats[playerNo].lastName, tmpProfile.lastName);
stats[playerNo].atbat += tmpProfile.atbat;
stats[playerNo].hits += tmpProfile.hits;
stats[playerNo].walks += tmpProfile.walks;
stats[playerNo].runs += tmpProfile.runs;
}
/* exercise: compute the average */
fclose(dataFile);
for(i=0; i<PLAYERS_NO; ++i)
{
if ( stats[i].name[0] == '\0' )
continue;
printf("%d %s %s %d %d %d %d\n",
i,
stats[i].name,
stats[i].lastName,
stats[i].atbat,
stats[i].hits,
stats[i].walks,
stats[i].runs);
}
return 0;
}
The first rule of programming: Divide and conquer.
So you need to identify individual operations. One such operation is "load one row of input", another is "look up a player". If you have some of those operations (more will come up as you go), you can start building your program:
while( more_input ) {
row = load_one_row()
player = find_player( row.name )
if( !player ) {
player = create_player( row.name )
add_player( player )
}
... do something with row and player ...
}
when you have that, you can start to write all the functions.
An important point here is to write test cases. Start with a simple input and test the code to read a row. Do you get the correct results?
If so, test the code to find/create players.
The test cases make sure that you can forget about code that already works.
Use a framework like Check for this.
If I were doing this, I'd start with a structure that only held one "set" of data, then create an array of those structs:
struct profile {
char name[NAMELEN];
char lname[NAMELEN];
int atbat;
int hits;
int walks;
int runs;
float batavg;
};
Since you're using the player's number as the index into an array, you don't need to store it into the structure too.
I think that will simplify the problem a little bit. You don't need to store multiple data items for a single player -- when you get a duplicate, you just ignore some of the new data (like the names, which should be identical) and sum up the others (e.g., at-bats, hits).

Resources