Link to home
Start Free TrialLog in
Avatar of crazy4s
crazy4s

asked on

Add a new file into the previous file

Hi all,
I'm now currently at the last stage of assignment where the user has to input a file name and that my program will reads this file and write it to the existing database file (will be continue from the 1st file) and then perform sort and then write it to the directory file.
Can someone lead me on how to do this? Any help will be greatly appreciated:)

this is what i have so far. I'll be having 2 files( AllCountries1.txt and AllCountries2.txt)
#include	<stdio.h>
#include 	<string.h>
#include 	<stdlib.h>
#include 	"ourhdr.h"

typedef struct				// Country Data struct declaration
    	{  	
		char code[4]; 		// Country Code 
       		char name[50];		// Country Name
		float life_expectancy;	// Life Expentancy of the Country's citizen
		int pop;		// Country's Population
    	} DATATYPE;

typedef struct				// Index Data struct declaration
	{
		char code[4];		
		long int offset;	// offset of the data
	} INDEX;

INDEX StructArray[300];	// for a lot of them
DATATYPE ActualStruct; // for a single struct

/***********************Index Copy function************************************************/

void indexCopy(INDEX* dest, INDEX src)
{
  strcpy(dest->code, src.code);
  dest->offset = src.offset;
} 

/*************************Insertion Sort function******************************************/

void sort(INDEX SortArray[], int n)
{
	int j;
	for(j=0; j < n;j++)
	{
		int k;
		INDEX temp; //Create a blank index data object
                indexCopy(&temp, SortArray[j]); //copy the data from the current line
		k = j-1;
		while (strcmp(SortArray[k].code, temp.code) >= 0 && k>=0)
		{
			indexCopy(&SortArray[k+1], SortArray[k]); //Now move them over
			k = k - 1;
		}
		indexCopy(&SortArray[k+1], temp);//And move the temp one back in
	}
} 

/*************************Print Sorted Array**********************************************/
void printsort(int size)
{
	sort(StructArray,size);	// call sort function
	int i;
	printf("Country Code     Offset\n");
	
	for (i=0; i<size; i++)
	{	
		printf("%s \t\t %u\n",StructArray[i].code, StructArray[i].offset);
	}
}

/************************Search Function by Country Code*********************************/
void search(int size)
{
	int mid, lower = 0, upper = size, flag = 1;
	INDEX cc;
	printf("Enter Country Code to search: ");
	scanf("%s", &cc);

	for(mid = (lower+upper)/2; lower <= upper; mid = (lower + upper)/2)
	{
		if(strcmp(StructArray[mid].code, cc.code) == 0)		// compare the input with the sorted array
		{
			printf("The country code is at position %d in the array at offset %u.\n", mid, StructArray[mid].offset);
			flag = 0;
			break;
		}
		if(strcmp(StructArray[mid].code, cc.code) > 0)		// compare the input with the sorted array
			upper = mid - 1;
		else
			lower = mid + 1;
	}
	
	if (flag)
		printf("Elements not found.");				// print this if the input is not in the array	
}
	

/***************************Main Function********************************************/

int main() 
{ 
	int i = 0;
	int size = 0;
	FILE *FI, *FO, *FO2;
	char Line[1000];  // NO input line (delimited by \n) is longer than 1000

	char * Tok;         // token from line
	if((FI = fopen("AC1.txt", "r")) == NULL) // open a stream from "countries"
    		err_sys("Open Fail\n");

	if((FO = fopen("DATABASE.txt", "wb")) == NULL) // open a stream from "countries"
    		err_sys("Open DATABASE Fail\n");

	if((FO2 = fopen("DIRECTORY.txt", "w+")) == NULL) // open a stream from "countries"
    		err_sys("Open DIRECTORY Fail\n");

    while ( fgets( (char *) Line,1000,FI) != NULL) // fill buffer up to newline or eof or error
    {

	Tok = strtok( Line ,",\n"); 	// skip ID number

        Tok = strtok( NULL ,",\n"); 	// this should get the country code 
        ActualStruct.code[0] = Tok[0];
        ActualStruct.code[1] = Tok[1];
        ActualStruct.code[2] = Tok[2];
        ActualStruct.code[3] = 0; 	// To create "string" 

	Tok = strtok( NULL ,",\n"); 	// this should get the country name 
        strncpy(&ActualStruct.name[0],Tok,50);	// copy string at most 50 chars

	Tok = strtok( NULL ,",\n"); 	// skip
	Tok = strtok( NULL ,",\n"); 	// skip 
	Tok = strtok( NULL ,",\n"); 	// skip
	Tok = strtok( NULL ,",\n"); 	// skip 

	Tok = strtok( NULL ,",\n"); 	// this should get the population
	ActualStruct.pop = atoi(Tok);	// convert string to integer

        Tok = strtok( NULL ,",\n"); 	// this one should get life expectancy
        ActualStruct.life_expectancy = atof(Tok);	// convert string to a floating point number

	strcpy(StructArray[i].code, ActualStruct.code);	// get the current code 
	StructArray[i].offset = ftell(FO);             	// get the current offset in the DATABASE file 

	if (fwrite(&ActualStruct, sizeof(DATATYPE),1,FO) != 1)  // write the struct to the DATABASE file 
		err_sys("fwrite error");

	i++;
	size = i;
	}

/****************************Sort the array and write into DIRECTORY*****************************/

	sort(StructArray,size);	// call sort function
	
	for (i=0; i<size; i++)
	{	
		if (fwrite(&StructArray[i], sizeof(INDEX),1,FO2) != 1)  // write the struct to the DIRECTORY file 
			err_sys("fwrite error");
	}

/*********************************************MENU************************************************/

	int c = -1;
	while( c != 4)
	{
		printf("Please select an option (1 to 4):\n");
		printf("1. Add to the DATABASE\n");
		printf("2. Search the DATABASE\n");
		printf("3. List all the countries in DATABASE by ordered Country Code\n");
		printf("4. Press q to exit\n");
		fflush(stdin);
		c = -1;		// error value if scanf fails
		scanf("%d", &c);
		switch (c)
		{
			case 1:
				break;
			case 2:
				search(size);
				break;
			case 3: 
				printsort(size);
				break;
			case 4:
				puts("Exiting program!");
				return 0;
			default:
				printf("\nNot implemented yet!");
		}
		return c;
	}

	if (fclose(FI))				// close file descriptor FI
		err_sys("Close error\n");	
	if (fclose(FO))				// close file descriptor FO
		err_sys("Close error\n");	
	if (fclose(FO2))			// close file descriptor FO2
		err_sys("Close error\n");

    	printf("------THE END------ \n");  // and this if not error :) 

}

Open in new window

Avatar of TommySzalapski
TommySzalapski
Flag of United States of America image

Make sure to close any open file before opening it differently. To add data to a file you need to open it for appending not writing like
fp=fopen("c:\\test.txt", "a")
I wouldn't try to open as "w+" and try to read and write.
I would
open as "r"
do all the reading
close the file
open as "a"
append (write) all the new data
close the file.
If you get w+ working for you, then go ahead, but I think it's easier the other way.
Avatar of crazy4s
crazy4s

ASKER

because directory is an empty file and i need to write the sorted country code and offset into it.
and read the directory into memory and then open back again and read it for searching purpose.
oops feeling that something has went wrong in my search func, i think i'm searching on the array instead of the directory file?
between is it possible to search on the directory file using country code?
Avatar of crazy4s

ASKER

i would like to ask a question.
when we write a new file to the existing file, the new file is a CSV file, so that means we need to go through all the steps again (token, get the 4 fields, put into the array and sort it again) izzit?
so after the fopen we need to perform fwrite izzit? hmm something like tat
FILE *fp;
fp = fopen("1st_file","a");       <-- do we open the directory file or what file should we open to modified?
fwrite("2nd_file", sizeof(DATATYPE),1,fp)  <-- not sure whether to put DATATYPE or INDEX?

any explanations will be greatly appreciated:)
Thanks.
I'm not sure exactly what you are trying to do so it's a little hard to answer the questions. If you can explain (without code) what you are trying to do with the files then I can give a better answer.

That said, you shouldn't need to reopen the file for reading at all. When you open the file, you put the data somewhere and you search that. You're not searching the file, you're searching the array. The array doesn't go away when you close the file. I think you want to do it like this

Open the file for reading.
Read all the data into the arrays.
Close the file.
Add data/sort data/whatever you need to do.
Search the arrays.
Program is quit by the user.
Open the file for appending.
Add the data to the file
Close the file.

Actually, I think you want to replace the entire file with the sorted data/new data don't you? You don't want to keep appending data. When you read it into the array and modify the array all the data is there.
i think i'm searching on the array instead of the directory file?
This is how it is usually done. Searching a file is a massive waste of time (reading and writing files takes a lot longer than messing with arrays since the array is in RAM and the file is on the hard drive).

between is it possible to search on the directory file using country code?
You can search based on anything. Just loop through the array and look for it.

when we write a new file to the existing file, the new file is a CSV file, so that means we need to go through all the steps again (token, get the 4 fields, put into the array and sort it again) izzit?
Sort of. You should set it up so you read the file at the beginning of the program and write to it at the end. So the only time you would need to do any token stuff again would be when the program is run again (so the code only runs once per run of the program)

so after the fopen we need to perform fwrite izzit?
You should do fopen, fread (into array, etc), fclose. fopen, fwrite, fclose. Always like that.

fp = fopen("1st_file","a");       <-- do we open the directory file or what file should we open to modified?
This is what I need the details to be able to explain. What are you trying to do?

fwrite("2nd_file", sizeof(DATATYPE),1,fp)  <-- not sure whether to put DATATYPE or INDEX?
Whichever one you are writing.
Avatar of crazy4s

ASKER

well i'll just paste what he sent us cos i might be misunderstand what he wants:

Part I) You will read the "countries" data and create a sorted array of structs, each of which contains, Name, Country Code henceforth known as CC (e.g. "ALG"), life expectancy, and population. Demonstrate that you can search the array by CC.

Part II)You will write the structs to a binary file and write another file, a kind of directory or index file. The fwrite function allows 'binary' i/o to write each struct. The directory file will contain the offsets in the binary file instead of subscripts in the array from part I. You will then close these two files.

Part III) Open the files created in Part II. Read the 'directory' into memory, some array(s), and use it to retrieve country data as per user request. Repeat until unamused.

Part IV) add some additional countries to the existing scheme. Close files, reopen, reamuse.
Avatar of crazy4s

ASKER

so you meant if i have an additional file I should have read that first and write it to the end of the existing file then only do token and sort? if the user didn't input any additional file that means the prog will just read the existing file, do token and sort? is that what should be meant?
Okay. That is what I thought. You don't need to add data to an existing file ever. You always overwrite the files. This is how I interpret it:

Read the csv file into an array of your DATATYPE structs.
Sort the data.
Search the array by CC.
Dump the data into the binary file.
Write the codes and offsets into a directory file.
Close all the files.
Read the directory file into a struct of your INDEX types.
Open the binary file for reading.
Let the user search for a country code and use the offset to pull just that country into your struct.
Close all files.

The way I read part 4 you just add some data into the csv file and do the whole thing again.
Avatar of crazy4s

ASKER

so what I have in my code now

1) Read the csv file into an array of your DATATYPE structs. <- yes, done!
2) Sort the data. <- yes,done!
3) Search the array by CC. < - yes, done!
4) Dump the data into the binary file. <- is this supposed to be sorted already? as i remember he says
                                                               this binary file should have the 4 fields of the structs with the o
                                                                offset too, that's why i fwrite the DATATYPE struct in the
                                                                while loop?
5) Write the codes and offsets into a directory file. <--this should be the sorted array
                                                                                      yes i think i've already done this
                                                                                      is it correct to write it like tat
/****************************Sort the array and write into DIRECTORY*****************************/

	sort(StructArray,size);	// call sort function
	
	for (i=0; i<size; i++)
	{	
		if (fwrite(&StructArray[i], sizeof(INDEX),1,FO2) != 1)  // write the struct to the DIRECTORY file 
			err_sys("fwrite error");
	}

Open in new window

6) Close all the files. <-- do i close before showing the menu?
7) Read the directory file into a struct of your INDEX types. <-- this is the one i should put into my
                                                                                                      code now? can you explain more on
                                                                                                      this?
8) Open the binary file for reading. <-- what is the use of opening this file?
9) Let the user search for a country code and use the offset to pull just that country into your struct.
     <- this should be my option 2 in my menu?
Close all files.
Avatar of crazy4s

ASKER

for part 4 if the user input a new txt file (user choose option 1 in the menu page)how should i write it in order to get the whole program to run it again?
Okay. I think I see where the confusion is.
This assignment is trying to teach you about indexing in files. So here is what is supposed to happen in more detail:
You load in a csv or text file or whatever (either by the user hitting a menu command or the default one when the program first runs). This you say you have done but I only see an array of INDEX type. You are missing most of the data.
Your two structs are perfect, don't change them. However you also need a DATATYPE array to store all the data. This data gets written into the binary file. The offsets don't go into the binary file directly. The offsets are to point to where the data is in the binary file.
Note that the code is 4 bytes, the name is 50 bytes, the float and int are 4 bytes each (on most computers) so _sizeof(DATATYPE) should give you 62. So your binary file will look something like this (Note I'm using 0 to be the null character that means you are at the end of a string):
DZA0Algeria0sdhfjhsakfjdfnsjf########AGO0Angola0ksdfhjsdfkfsdjfshfjskdfk########BEN0Benin0sadhfhasdjkfksdhfsdjfhsdhf########
Remember the rest of the 50 characters in the name are junk and the integer won't look like a number in the binary file (I used # to represent where the bytes would be).
So lets say I want to find the population of Benin. I don't want to load the whole file, just the part about Benin. Well, I have a directory has just the CC and the offset. It says BEN has an offset of 124. So I jump to character 124 of the binary file and read in one struct. Boom, it's Benin.

In this example it's not a big deal to just open the whole thing, but what if you had 500 pieces of data for each country? What if you had people instead of countries and had the whole U.S. population in your database? You don't want to load the whole thing. Just take an index (like social security number) and find the one record in the file that you actually want.

So your index array (and directory file) should just have the code and the offset from the binary file. Since you weren't given a format to use for that file, just use something easy (hint: don't use csv).
Avatar of crazy4s

ASKER

ok so now i need to have a DATATYPE array and this array should have the 4 fields ryte?
and do i do it just like the way i do for INDEX StructArray[300]?
let's say:
DATATYPE DBArray[300];
and then in the while loop:
strcpy(DBArray(i).code, ActualStruct.code);
strcpy(DBArray(i).name, ActualStruct.name);
DBArray(i).pop, ActualStruct.pop;
DBArray(i).life_expectancy, ActualStruct.life_expectancy

so after having this DATATYPE array then only I write into the binary file? izzit?

yes i know that the binary file look something like as previously I've taken a look when i write the struct into the binary file. but previously when I try to run the prog n show the offset, it shows that every struct is 64 bytes instead of 62?
Avatar of crazy4s

ASKER

but the given the 2 files are csv file.
so after having this DATATYPE array then only I write into the binary file? izzit?
Yes. You just write the DATATYPE array into the binary file.

it shows that every struct is 64 bytes instead of 62?
Then use 64. That was just for the example. I tried it out and got the same result. It's because of the way the computer works behind the scenes. You are using a 32-bit system so sometimes it likes to fill with junk up to the nearest multiple of 4 bytes. But that doesn't matter. Just use sizeof in the code when you build the offset and it will work on any machine. (Technically, the binary file built on one computer might not load properly on another, but you don't care since you aren't selling this program to millions of users).
Avatar of crazy4s

ASKER

ok so this is what I've now: did I get the first 6 things that you've mentioned correct?
#include	<stdio.h>
#include 	<string.h>
#include 	<stdlib.h>
#include 	"ourhdr.h"

typedef struct				// Country Data struct declaration
    	{  	
		char code[4]; 		// Country Code 
       		char name[50];		// Country Name
		float life_expectancy;	// Life Expentancy of the Country's citizen
		int pop;		// Country's Population
    	} DATATYPE;

typedef struct				// Index Data struct declaration
	{
		char code[4];		
		long int offset;	// offset of the data
	} INDEX;

INDEX StructArray[300];		// INDEX array
DATATYPE ActualStruct; 		// for a single struct
DATATYPE DatabaseArray[300]; 	// DATATYPE array

/***********************Index Copy function************************************************/

void indexCopy(INDEX* dest, INDEX src)
{
  strcpy(dest->code, src.code);
  dest->offset = src.offset;
} 

/*************************Insertion Sort function******************************************/

void sort(INDEX SortArray[], int n)
{
	int j;
	for(j=0; j < n;j++)
	{
		int k;
		INDEX temp; //Create a blank index data object
                indexCopy(&temp, SortArray[j]); //copy the data from the current line
		k = j-1;
		while (strcmp(SortArray[k].code, temp.code) >= 0 && k>=0)
		{
			indexCopy(&SortArray[k+1], SortArray[k]); //Now move them over
			k = k - 1;
		}
		indexCopy(&SortArray[k+1], temp);//And move the temp one back in
	}
} 

/*************************Print Sorted Array**********************************************/
void printsort(int size)
{
	sort(StructArray,size);	// call sort function
	int i;
	printf("Country Code     Offset\n");
	
	for (i=0; i<size; i++)
	{	
		printf("%s \t\t %u\n",StructArray[i].code, StructArray[i].offset);
	}
}

/************************Search Function by Country Code*********************************/
void search(int size)
{
	int mid, lower = 0, upper = size, flag = 1;
	INDEX cc;
	printf("Enter Country Code to search: ");
	scanf("%s", &cc);

	for(mid = (lower+upper)/2; lower <= upper; mid = (lower + upper)/2)
	{
		if(strcmp(StructArray[mid].code, cc.code) == 0)		// compare the input with the sorted array
		{
			printf("The country code is at position %d in the array at offset %u.\n", mid, StructArray[mid].offset);
			flag = 0;
			break;
		}
		if(strcmp(StructArray[mid].code, cc.code) > 0)		// compare the input with the sorted array
			upper = mid - 1;
		else
			lower = mid + 1;
	}
	
	if (flag)
		printf("Elements not found.");				// print this if the input is not in the array	
}
	

/***************************Main Function********************************************/

int main() 
{ 
	int i = 0;
	int size = 0;
	FILE *FI, *FO, *FO2;
	char Line[1000];  // NO input line (delimited by \n) is longer than 1000

	char * Tok;         // token from line
	if((FI = fopen("AC1.txt", "r")) == NULL) // open a stream from "countries"
    		err_sys("Open Fail\n");

	if((FO = fopen("DATABASE.txt", "wb")) == NULL) // open a stream from "countries"
    		err_sys("Open DATABASE Fail\n");

	if((FO2 = fopen("DIRECTORY.txt", "w+")) == NULL) // open a stream from "countries"
    		err_sys("Open DIRECTORY Fail\n");

    while ( fgets( (char *) Line,1000,FI) != NULL) // fill buffer up to newline or eof or error
    {

	Tok = strtok( Line ,",\n"); 	// skip ID number

        Tok = strtok( NULL ,",\n"); 	// this should get the country code 
        ActualStruct.code[0] = Tok[0];
        ActualStruct.code[1] = Tok[1];
        ActualStruct.code[2] = Tok[2];
        ActualStruct.code[3] = 0; 	// To create "string" 

	Tok = strtok( NULL ,",\n"); 	// this should get the country name 
        strncpy(&ActualStruct.name[0],Tok,50);	// copy string at most 50 chars

	Tok = strtok( NULL ,",\n"); 	// skip
	Tok = strtok( NULL ,",\n"); 	// skip 
	Tok = strtok( NULL ,",\n"); 	// skip
	Tok = strtok( NULL ,",\n"); 	// skip 

	Tok = strtok( NULL ,",\n"); 	// this should get the population
	ActualStruct.pop = atoi(Tok);	// convert string to integer

        Tok = strtok( NULL ,",\n"); 	// this one should get life expectancy
        ActualStruct.life_expectancy = atof(Tok);	// convert string to a floating point number

	strcpy(DatabaseArray[i].code,ActualStruct.code);
	strcpy(DatabaseArray[i].name,ActualStruct.name);
	DatabaseArray[i].pop = ActualStruct.pop;
	DatabaseArray[i].life_expectancy = ActualStruct.life_expectancy;	

	strcpy(StructArray[i].code, ActualStruct.code);	// get the current code 
	StructArray[i].offset = ftell(FO);             	// get the current offset in the DATABASE file 

	i++;
	size = i;
	}

/*******************Write into DATABASE, Sort the INDEX array and write into DIRECTORY and close both files*******************/
	if (fwrite(&DatabaseArray[i], sizeof(DATATYPE),1,FO) != 1)  // write the struct to the DATABASE file 
		err_sys("fwrite error");

	sort(StructArray,size);	// call sort function
	
	for (i=0; i<size; i++)
	{	
		if (fwrite(&StructArray[i], sizeof(INDEX),1,FO2) != 1)  // write the struct to the DIRECTORY file 
			err_sys("fwrite error");
	}

	if (fclose(FO))				// close file descriptor FO
		err_sys("Close error\n");	
	if (fclose(FO2))			// close file descriptor FO2
		err_sys("Close error\n");

/**************Open BINARY and DIRECTORY files and read DIRECTORY file into memory****************/

	FILE *infile;		// declare an index file pointer
	char *buffer;
	long numbytes;
	if((infile = fopen("DIRECTORY.txt", "rb")) == NULL) // open a stream from "countries"
    		err_sys("Open DIRECTORY Fail\n");

	fseek(infile,0,SEEK_END);
	numbytes = ftell(infile);	// get the number of bytes
	
	fseek(infile,0, SEEK_SET);	// reset the file position indicator to the beginning of the file

	buffer = (char*)calloc(numbytes,sizeof(char)); 	// grab sufficient memory for the buffer 
							// to hold the text

	fread(buffer,sizeof(char),numbytes,infile);	// copy all the text into the buffer
	fclose(infile);

	free(buffer);	// free the memory we used for the buffer
	
	

/*********************************************MENU************************************************/

	int c = -1;
	while( c != 4)
	{
		printf("Please select an option (1 to 4):\n");
		printf("1. Add to the DATABASE\n");
		printf("2. Search the DATABASE\n");
		printf("3. List all the countries in DATABASE by ordered Country Code\n");
		printf("4. Press q to exit\n");
		fflush(stdin);
		c = -1;		// error value if scanf fails
		scanf("%d", &c);
		switch (c)
		{
			case 1:
				break;
			case 2:
				search(size);
				break;
			case 3: 
				printsort(size);
				break;
			case 4:
				puts("Exiting program!");
				return 0;
			default:
				printf("\nNot implemented yet!");
		}
		return c;
	}

	if (fclose(FI))				// close file descriptor FI
		err_sys("Close error\n");	


    	printf("------THE END------ \n");  // and this if not error :) 

}

Open in new window

Looks pretty good.
Remember that when you sort it and put it into a binary file all the offsets will be messed up so you'll have to recalculate them.
Avatar of crazy4s

ASKER

how if the data in the binary file is not sorted only the directory file is sorted...then when we search we know the offset of where the data live in the binary file?
Avatar of crazy4s

ASKER

and now what you meant by this >> Read the directory file into a struct of your INDEX types.
isn't the directory file is already the INDEX array?
how if the data in the binary file is not sorted only the directory file is sorted
That would work just fine. However, that's not how I read the assignment. Perhaps you should ask your instructor that question.

isn't the directory file is already the INDEX array?
That's the idea.

By the way, in your code I see that you get the offset while reading in the csv? (line 141) That's not right. The offset is supposed to refer to the binary file (which you create in the next section of code).
Avatar of crazy4s

ASKER

then how about putting like that
	strcpy(DatabaseArray[i].code,ActualStruct.code);	// get the current code 
	strcpy(DatabaseArray[i].name,ActualStruct.name);	// get the current name
	DatabaseArray[i].pop = ActualStruct.pop;		// get the current population
	DatabaseArray[i].life_expectancy = ActualStruct.life_expectancy; // get the current life expectancy

	if (fwrite(&DatabaseArray[i], sizeof(DATATYPE),1,FO) != 1)  // write the struct to the DATABASE file 
		err_sys("fwrite error");

	strcpy(StructArray[i].code, ActualStruct.code);	// get the current code 
	StructArray[i].offset = ftell(FO);   

Open in new window

Avatar of crazy4s

ASKER

when i perform the search func by country code, how can i get the position offset of the INDEX array and read from the binary file at that offset and then print out the 4 fields.
void search(int size)
{
	int mid, lower = 0, upper = size, flag = 1;
	INDEX cc;
	printf("Enter Country Code to search: ");
	scanf("%s", &cc);

	for(mid = (lower+upper)/2; lower <= upper; mid = (lower + upper)/2)
	{
		if(strcmp(StructArray[mid].code, cc.code) == 0)		// compare the input with the sorted array
		{
			printf("The country code is at position %d in the array at offset %u.\n", mid, StructArray[mid].offset);
			printf("%s %s %u %f\n", DatabaseArray[mid].code, DatabaseArray[mid].name, DatabaseArray[mid].pop, DatabaseArray[mid].life_expectancy); // i know this is wrong
			flag = 0;
			break;
		}
		if(strcmp(StructArray[mid].code, cc.code) > 0)		// compare the input with the sorted array
			upper = mid - 1;
		else
			lower = mid + 1;
	}
	
	if (flag)
		printf("Elements not found.");				// print this if the input is not in the array	
}
	

Open in new window

(from 2 posts ago) then how about putting like that
Close. The only problem is you write it then look at where you are in the file. You just need to put line 10 before line 6.

(from the last post)how can i get the position offset of the INDEX array and read from the binary file at that offset and then print out the 4 fields.
You already have StructArray[mid].offset in the if statement. That's perfect. Now you just need to open the binary file and move to position StructArray[mid].offset. Then read (in binary format) into ActualStruct. All the data will then be loaded into it and you can display it as you see fit. Note: in the current state, it may find the one directly after the right one (see above)
Avatar of crazy4s

ASKER

how do i move to position StructArray[mid].offset and read into Actual Struct?
can you show me some ex?
void search(int size)
{
	int mid, lower = 0, upper = size, flag = 1;
	INDEX cc;
	FILE *FI;
	if((FI = fopen("DATABASE.txt", "r")) == NULL) // open DATABASE for read
    		err_sys("Open DATABASE Fail\n");
	printf("Enter Country Code to search: ");
	scanf("%s", &cc);

	for(mid = (lower+upper)/2; lower <= upper; mid = (lower + upper)/2)
	{
		if(strcmp(StructArray[mid].code, cc.code) == 0)		// compare the input with the sorted array
		{
			printf("The country code is at position %d in the array at offset %u.\n", mid, StructArray[mid].offset);
			printf("%s %s %u %f\n", DatabaseArray[mid].code, DatabaseArray[mid].name, DatabaseArray[mid].pop, DatabaseArray[mid].life_expectancy);
			flag = 0;
			break;
		}
		if(strcmp(StructArray[mid].code, cc.code) > 0)		// compare the input with the sorted array
			upper = mid - 1;
		else
			lower = mid + 1;
	}
	
	if (flag)
		printf("Elements not found.");				// print this if the input is not in the array	
}

Open in new window

Avatar of crazy4s

ASKER

can i do something like this
			lseek(FI,StructArray[mid].offset,SEEK_CUR);			

Open in new window

Avatar of crazy4s

ASKER

erm no wait should be like this
void search(int size)
{
	int mid, lower = 0, upper = size, flag = 1;
	INDEX cc;
	FILE *FI;
	if((FI = fopen("DATABASE.txt", "r")) == NULL) // open DATABASE for read
    		err_sys("Open DATABASE Fail\n");
	printf("Enter Country Code to search: ");
	scanf("%s", &cc);

	for(mid = (lower+upper)/2; lower <= upper; mid = (lower + upper)/2)
	{
		if(strcmp(StructArray[mid].code, cc.code) == 0)		// compare the input with the sorted array
		{
			printf("The country code is at position %d in the array at offset %u.\n", mid, StructArray[mid].offset);
                        fseek(FI,StructArray[mid].offset,SEEK_CUR);
                        fread((&DatabaseArray[mid], sizeof(DATATYPE),1,FI)
			printf("%s %s %u %f\n", DatabaseArray[mid].code, DatabaseArray[mid].name, DatabaseArray[mid].pop, DatabaseArray[mid].life_expectancy);
			flag = 0;
			break;
		}
		if(strcmp(StructArray[mid].code, cc.code) > 0)		// compare the input with the sorted array
			upper = mid - 1;
		else
			lower = mid + 1;
	}
	
	if (flag)
		printf("Elements not found.");				// print this if the input is not in the array	

	if (fclose(FI))				// close file descriptor FI
		err_sys("Close error\n");
}

Open in new window

Avatar of crazy4s

ASKER

ok i got the 4 fields printed out!XD
so now the last step is if the user select option 1 which is to add a new file to the existing file and run then it again.... i got no idea on how to do this
#include	<stdio.h>
#include 	<string.h>
#include 	<stdlib.h>
#include 	"ourhdr.h"

typedef struct				// Country Data struct declaration
    	{  	
		char code[4]; 		// Country Code 
       		char name[50];		// Country Name
		float life_expectancy;	// Life Expentancy of the Country's citizen
		int pop;		// Country's Population
    	} DATATYPE;

typedef struct				// Index Data struct declaration
	{
		char code[4];		
		long int offset;	// offset of the data
	} INDEX;

INDEX StructArray[300];	// for a lot of them
DATATYPE ActualStruct; // for a single struct
DATATYPE DatabaseArray[300]; 	// DATATYPE array

/***********************Index Copy function************************************************/

void indexCopy(INDEX* dest, INDEX src)
{
  strcpy(dest->code, src.code);
  dest->offset = src.offset;
} 

/*************************Insertion Sort function******************************************/

void sort(INDEX SortArray[], int n)
{
	int j;
	for(j=0; j < n;j++)
	{
		int k;
		INDEX temp; //Create a blank index data object
                indexCopy(&temp, SortArray[j]); //copy the data from the current line
		k = j-1;
		while (strcmp(SortArray[k].code, temp.code) >= 0 && k>=0)
		{
			indexCopy(&SortArray[k+1], SortArray[k]); //Now move them over
			k = k - 1;
		}
		indexCopy(&SortArray[k+1], temp);//And move the temp one back in
	}
} 

/*************************Print Sorted Array**********************************************/
void printsort(int size)
{
	sort(StructArray,size);	// call sort function
	int i;
	printf("Country Code     Offset\n");
	
	for (i=0; i<size; i++)
	{	
		printf("%s \t\t %u\n",StructArray[i].code, StructArray[i].offset);
	}
}

/************************Search Function by Country Code*********************************/
void search(int size)
{
	int mid, lower = 0, upper = size, flag = 1;
	INDEX cc;
	FILE *FI;
	if((FI = fopen("DATABASE.txt", "r")) == NULL) // open DATABASE for read
    		err_sys("Open DATABASE Fail\n");
	printf("Enter Country Code to search: ");
	scanf("%s", &cc);

	for(mid = (lower+upper)/2; lower <= upper; mid = (lower + upper)/2)
	{
		if(strcmp(StructArray[mid].code, cc.code) == 0)		// compare the input with the sorted array
		{
			printf("The country code is at position %d in the array at offset %u in the binary file.\n", mid, StructArray[mid].offset);
                        fseek(FI,StructArray[mid].offset,SEEK_CUR);	//seek the offset in the binary file
                        fread(&DatabaseArray[mid], sizeof(DATATYPE),1,FI);	// read the struct of array from binary file (4 fields)
			printf("%s %s %u %f\n", DatabaseArray[mid].code, DatabaseArray[mid].name, DatabaseArray[mid].pop, DatabaseArray[mid].life_expectancy);
			flag = 0;
			break;
		}
		if(strcmp(StructArray[mid].code, cc.code) > 0)		// compare the input with the sorted array
			upper = mid - 1;
		else
			lower = mid + 1;
	}
	
	if (flag)
		printf("Elements not found.");				// print this if the input is not in the array	

	if (fclose(FI))				// close file descriptor FI
		err_sys("Close error\n");
}
	

/***************************Main Function********************************************/

int main(int argc, char *argv[]) 
{ 
	int i = 0;
	int size = 0;
	FILE *FI, *FO, *FO2;
	char Line[1000];  // NO input line (delimited by \n) is longer than 1000

	char * Tok;         // token from line
	if (argc!= 2)
		printf("MYAS2 <filename>\n") ;
	
	if((FI = fopen(argv[1], "r")) == NULL) // open a stream from "countries"
    		err_sys("Open Fail\n");

	if((FO = fopen("DATABASE.txt", "wb")) == NULL) // open a stream from "countries"
    		err_sys("Open DATABASE Fail\n");

	if((FO2 = fopen("DIRECTORY.txt", "w+")) == NULL) // open a stream from "countries"
    		err_sys("Open DIRECTORY Fail\n");

    while ( fgets( (char *) Line,1000,FI) != NULL) // fill buffer up to newline or eof or error
    {

	Tok = strtok( Line ,",\n"); 	// skip ID number

        Tok = strtok( NULL ,",\n"); 	// this should get the country code 
        ActualStruct.code[0] = Tok[0];
        ActualStruct.code[1] = Tok[1];
        ActualStruct.code[2] = Tok[2];
        ActualStruct.code[3] = 0; 	// To create "string" 

	Tok = strtok( NULL ,",\n"); 	// this should get the country name 
        strncpy(&ActualStruct.name[0],Tok,50);	// copy string at most 50 chars

	Tok = strtok( NULL ,",\n"); 	// skip
	Tok = strtok( NULL ,",\n"); 	// skip 
	Tok = strtok( NULL ,",\n"); 	// skip
	Tok = strtok( NULL ,",\n"); 	// skip 

	Tok = strtok( NULL ,",\n"); 	// this should get the population
	ActualStruct.pop = atoi(Tok);	// convert string to integer

        Tok = strtok( NULL ,",\n"); 	// this one should get life expectancy
        ActualStruct.life_expectancy = atof(Tok);	// convert string to a floating point number

	strcpy(DatabaseArray[i].code,ActualStruct.code);	// get the current code 
	strcpy(DatabaseArray[i].name,ActualStruct.name);	// get the current name
	DatabaseArray[i].pop = ActualStruct.pop;		// get the current population
	DatabaseArray[i].life_expectancy = ActualStruct.life_expectancy; // get the current life expectancy

	strcpy(StructArray[i].code, ActualStruct.code);	// get the current code 
	StructArray[i].offset = ftell(FO);             	// get the current offset in the DATABASE file 

	if (fwrite(&DatabaseArray[i], sizeof(DATATYPE),1,FO) != 1)  // write the struct to the DATABASE file 
		err_sys("fwrite error");

	i++;
	size = i;
	}

/****************************Sort the array and write into DIRECTORY*****************************/

	sort(StructArray,size);	// call sort function
	
	for (i=0; i<size; i++)
	{	
		if (fwrite(&StructArray[i], sizeof(INDEX),1,FO2) != 1)  // write the struct to the DIRECTORY file 
			err_sys("fwrite error");
	}

	if (fclose(FI))				// close file descriptor FI
		err_sys("Close error\n");	
	if (fclose(FO))				// close file descriptor FO
		err_sys("Close error\n");	
	if (fclose(FO2))			// close file descriptor FO2
		err_sys("Close error\n");

/***********************************read DIRECTORY file into memory******************************/

	FILE *infile;		// declare an index file pointer
	char *buffer;
	long numbytes;

	if((infile = fopen("DIRECTORY.txt", "rb")) == NULL) // open a stream from "countries"
    		err_sys("Open DIRECTORY Fail\n");

	fseek(infile,0,SEEK_END);
	numbytes = ftell(infile);	// get the number of bytes
	
	fseek(infile,0, SEEK_SET);	// reset the file position indicator to the beginning of the file

	buffer = (char*)calloc(numbytes,sizeof(char)); 	// grab sufficient memory for the buffer 
							// to hold the text

	fread(buffer,sizeof(char),numbytes,infile);	// copy all the text into the buffer
	fclose(infile);

	free(buffer);	// free the memory we used for the buffer
	
/*********************************************MENU************************************************/

	int c = -1;
	while( c != 4)
	{
		printf("Please select an option (1 to 4):\n");
		printf("1. Add to the DATABASE\n");
		printf("2. Search the DATABASE\n");
		printf("3. List all the countries in DATABASE by ordered Country Code\n");
		printf("4. Press q to exit\n");
		fflush(stdin);
		c = -1;		// error value if scanf fails
		scanf("%d", &c);
		switch (c)
		{
			case 1:
                                printf("Filename(data that you would like to add in): ");
				break;
			case 2:
				search(size);
				break;
			case 3: 
				printsort(size);
				break;
			case 4:
				puts("Exiting program!");
				return 0;
			default:
				printf("\nNot implemented yet!");
		}
	}

    	printf("------THE END------ \n");  // and this if not error :) 

}

Open in new window

Avatar of crazy4s

ASKER

previously i only print the Country code and the offset (in printsort func) how can i edit this so that all the 4 fields will be printed out according to the country code?
void printsort(int size)
{
	sort(StructArray,size);	// call sort function
	FILE *FI;
	if((FI = fopen("DATABASE.txt", "r")) == NULL) // open DATABASE for read
    		err_sys("Open DATABASE Fail\n");
	int i;	
	for (i=0; i<size; i++)
	{	
              	fseek(FI,StructArray[i].offset,SEEK_CUR);	//seek the offset in the binary file
               	fread(&DatabaseArray[], sizeof(DATATYPE),1,FI);	// read the struct of array from binary file (4 fields)
		printf("%s %s %u %f %u\n", DatabaseArray[].code, DatabaseArray[].name, DatabaseArray[].pop, DatabaseArray[].life_expectancy, StructArray[i].offset);
	}
}

Open in new window


i know the problem is -> DatabaseArray[[what should i put here? i try to put (i) but its output like this].code
AGO Angola 12878000 38.299999 64
AGO Angola 12878000 38.299999 384
BEN Benin 6097000 50.200001 128
BWA Botswana 1622000 39.299999 320
IOT British Indian Ocean Territory 0 0.000000 192
BFA Burkina Faso 11937000 46.700001 0
BDI Burundi 6695000 46.200001 256

ASKER CERTIFIED SOLUTION
Avatar of TommySzalapski
TommySzalapski
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
so now the last step is if the user select option 1 which is to add a new file to the existing file and run then it again.... i got no idea on how to do this

Again, I think the assignment just asked you to run the whole thing on a new file.
Anyway, if they want to select a file with some extra countries just read them in like you did before and add them to the end of the database array. Then rebuild the entire binary file from scratch (or just append the new ones). But overwriting would be easier.

Again, I don't think you need to do that. I think you just need to quit and run again on a new file.
Avatar of crazy4s

ASKER

i tried but the output is like this?
AGO Angola 12878000 38.299999 64
AGO Angola 12878000 38.299999 384
AGO Angola 12878000 38.299999 128
AGO Angola 12878000 38.299999 320
AGO Angola 12878000 38.299999 192
AGO Angola 12878000 38.299999 0
AGO Angola 12878000 38.299999 256
If you open the binary file, what does it look like? Does it look right?
Also, you should be using
fseek(FI,StructArray[ i].offset,SEEK_SET);
not SEEK_CUR since you want to use the offset from the start not from the current location
Avatar of crazy4s

ASKER

ah yeah because every time it loops have to start again from the beginning of the file:D
aoww now i have to do this >>Anyway, if they want to select a file with some extra countries just read them in like you did before and add them to the end of the database array. Then rebuild the entire binary file from scratch (or just append the new ones).
this is the one he wants... but i have no idea where to start?
#include	<stdio.h>
#include 	<string.h>
#include 	<stdlib.h>
#include 	"ourhdr.h"

typedef struct				// Country Data struct declaration
    	{  	
		char code[4]; 		// Country Code 
       		char name[50];		// Country Name
		float life_expectancy;	// Life Expentancy of the Country's citizen
		int pop;		// Country's Population
    	} DATATYPE;

typedef struct				// Index Data struct declaration
	{
		char code[4];		
		long int offset;	// offset of the data
	} INDEX;

INDEX StructArray[300];	// for a lot of them
DATATYPE ActualStruct; // for a single struct
DATATYPE DatabaseArray[300]; 	// DATATYPE array

/***********************Index Copy function************************************************/

void indexCopy(INDEX* dest, INDEX src)
{
  strcpy(dest->code, src.code);
  dest->offset = src.offset;
} 

/*************************Insertion Sort function******************************************/

void sort(INDEX SortArray[], int n)
{
	int j;
	for(j=0; j < n;j++)
	{
		int k;
		INDEX temp; //Create a blank index data object
                indexCopy(&temp, SortArray[j]); //copy the data from the current line
		k = j-1;
		while (strcmp(SortArray[k].code, temp.code) >= 0 && k>=0)
		{
			indexCopy(&SortArray[k+1], SortArray[k]); //Now move them over
			k = k - 1;
		}
		indexCopy(&SortArray[k+1], temp);//And move the temp one back in
	}
} 

/*************************Print Sorted Array**********************************************/
void printsort(int size)
{
                      DATATYPE country;

	sort(StructArray,size);	// call sort function
	FILE *FI;
	if((FI = fopen("DATABASE.txt", "r")) == NULL) // open DATABASE for read
    		err_sys("Open DATABASE Fail\n");
	int i;
	printf("--------------------------------------------------------------------------------------------------------\n");
	printf("  CODE \t\t\t COUNTRY NAME \t\t\t   POPULATION      LIFE EXPECTANCY \t OFFSET\n");
	printf("--------------------------------------------------------------------------------------------------------\n");
	
	for (i=0; i<size; i++)
	{	
              	fseek(FI,StructArray[i].offset,SEEK_SET);	//seek the offset in the binary file
               	fread(&country, sizeof(DATATYPE),1,FI);	// read the struct of array from binary file (4 fields)
		printf("%5s%50s%15u%18f%15u\n", country.code, country.name, country.pop, country.life_expectancy, StructArray[i].offset);
	}
} 

/************************Search Function by Country Code*********************************/
void search(int size)
{
	int mid, lower = 0, upper = size, flag = 1;
	INDEX cc;
	FILE *FI;
	if((FI = fopen("DATABASE.txt", "r")) == NULL) // open DATABASE for read
    		err_sys("Open DATABASE Fail\n");
	printf("Enter Country Code to search: ");
	scanf("%s", &cc);

	for(mid = (lower+upper)/2; lower <= upper; mid = (lower + upper)/2)
	{
		if(strcmp(StructArray[mid].code, cc.code) == 0)		// compare the input with the sorted array
		{
			printf("The country code is at position %d in the array at offset %u in the binary file.\n", mid, StructArray[mid].offset);
                        fseek(FI,StructArray[mid].offset,SEEK_CUR);	//seek the offset in the binary file
                        fread(&DatabaseArray[mid], sizeof(DATATYPE),1,FI);	// read the struct of array from binary file (4 fields)
			printf("%s %s %u %f\n", DatabaseArray[mid].code, DatabaseArray[mid].name, DatabaseArray[mid].pop, DatabaseArray[mid].life_expectancy);
			flag = 0;
			break;
		}
		if(strcmp(StructArray[mid].code, cc.code) > 0)		// compare the input with the sorted array
			upper = mid - 1;
		else
			lower = mid + 1;
	}
	
	if (flag)
		printf("Elements not found.");				// print this if the input is not in the array	

	if (fclose(FI))				// close file descriptor FI
		err_sys("Close error\n");
}
	

/***************************Main Function********************************************/

int main(int argc, char *argv[]) 
{ 
	int i = 0;
	int size = 0;
	FILE *FI, *FO, *FO2;
	char Line[1000];  // NO input line (delimited by \n) is longer than 1000

	char * Tok;         // token from line
	//if (argc!= 2)
	//	printf("MYAS2 <filename>\n") ;
	
	if((FI = fopen("AC1.txt", "r")) == NULL) // open a stream from "countries"
    		err_sys("Open Fail\n");

	if((FO = fopen("DATABASE.txt", "wb")) == NULL) // open a stream from "countries"
    		err_sys("Open DATABASE Fail\n");

	if((FO2 = fopen("DIRECTORY.txt", "w+")) == NULL) // open a stream from "countries"
    		err_sys("Open DIRECTORY Fail\n");

    while ( fgets( (char *) Line,1000,FI) != NULL) // fill buffer up to newline or eof or error
    {

	Tok = strtok( Line ,",\n"); 	// skip ID number

        Tok = strtok( NULL ,",\n"); 	// this should get the country code 
        ActualStruct.code[0] = Tok[0];
        ActualStruct.code[1] = Tok[1];
        ActualStruct.code[2] = Tok[2];
        ActualStruct.code[3] = 0; 	// To create "string" 

	Tok = strtok( NULL ,",\n"); 	// this should get the country name 
        strncpy(&ActualStruct.name[0],Tok,50);	// copy string at most 50 chars

	Tok = strtok( NULL ,",\n"); 	// skip
	Tok = strtok( NULL ,",\n"); 	// skip 
	Tok = strtok( NULL ,",\n"); 	// skip
	Tok = strtok( NULL ,",\n"); 	// skip 

	Tok = strtok( NULL ,",\n"); 	// this should get the population
	ActualStruct.pop = atoi(Tok);	// convert string to integer

        Tok = strtok( NULL ,",\n"); 	// this one should get life expectancy
        ActualStruct.life_expectancy = atof(Tok);	// convert string to a floating point number

	strcpy(DatabaseArray[i].code,ActualStruct.code);	// get the current code 
	strcpy(DatabaseArray[i].name,ActualStruct.name);	// get the current name
	DatabaseArray[i].pop = ActualStruct.pop;		// get the current population
	DatabaseArray[i].life_expectancy = ActualStruct.life_expectancy; // get the current life expectancy

	strcpy(StructArray[i].code, ActualStruct.code);	// get the current code 
	StructArray[i].offset = ftell(FO);             	// get the current offset in the DATABASE file 

	if (fwrite(&DatabaseArray[i], sizeof(DATATYPE),1,FO) != 1)  // write the struct to the DATABASE file 
		err_sys("fwrite error");

	i++;
	size = i;
	}

/****************************Sort the array and write into DIRECTORY*****************************/

	sort(StructArray,size);	// call sort function
	
	for (i=0; i<size; i++)
	{	
		if (fwrite(&StructArray[i], sizeof(INDEX),1,FO2) != 1)  // write the struct to the DIRECTORY file 
			err_sys("fwrite error");
	}

	if (fclose(FI))				// close file descriptor FI
		err_sys("Close error\n");	
	if (fclose(FO))				// close file descriptor FO
		err_sys("Close error\n");	
	if (fclose(FO2))			// close file descriptor FO2
		err_sys("Close error\n");

/***********************************read DIRECTORY file into memory******************************/

	FILE *infile;		// declare an index file pointer
	char *buffer;
	long numbytes;

	if((infile = fopen("DIRECTORY.txt", "rb")) == NULL) // open a stream from "countries"
    		err_sys("Open DIRECTORY Fail\n");

	fseek(infile,0,SEEK_END);
	numbytes = ftell(infile);	// get the number of bytes
	
	fseek(infile,0, SEEK_SET);	// reset the file position indicator to the beginning of the file

	buffer = (char*)calloc(numbytes,sizeof(char)); 	// grab sufficient memory for the buffer 
							// to hold the text

	fread(buffer,sizeof(char),numbytes,infile);	// copy all the text into the buffer
	fclose(infile);

	free(buffer);	// free the memory we used for the buffer
	
/*********************************************MENU************************************************/

	int c = -1;
	while( c != 4)
	{
		printf("Please select an option (1 to 4):\n");
		printf("1. Add to the DATABASE\n");
		printf("2. Search the DATABASE\n");
		printf("3. List all the countries in DATABASE by ordered Country Code\n");
		printf("4. Press q to exit\n");
		fflush(stdin);
		c = -1;		// error value if scanf fails
		scanf("%d", &c);
		switch (c)
		{
			case 1:
                                printf("Filename(data that you would like to add in): ");
				break;
			case 2:
				search(size);
				break;
			case 3: 
				printsort(size);
				break;
			case 4:
				puts("Exiting program!");
				return 0;
			default:
				printf("\nNot implemented yet!");
		}
	}

}

Open in new window

Avatar of crazy4s

ASKER

btw do i really need this for my code? i don't really understand what's this for?
is because he mentioned to read the directory file into memory that's why i went and search the net on how to read a file into memory and get this code!
/***********************************read DIRECTORY file into memory******************************/

	FILE *infile;		// declare an index file pointer
	char *buffer;
	long numbytes;

	if((infile = fopen("DIRECTORY.txt", "rb")) == NULL) // open a stream from "countries"
    		err_sys("Open DIRECTORY Fail\n");

	fseek(infile,0,SEEK_END);
	numbytes = ftell(infile);	// get the number of bytes
	
	fseek(infile,0, SEEK_SET);	// reset the file position indicator to the beginning of the file

	buffer = (char*)calloc(numbytes,sizeof(char)); 	// grab sufficient memory for the buffer 
							// to hold the text

	fread(buffer,sizeof(char),numbytes,infile);	// copy all the text into the buffer
	fclose(infile);

	free(buffer);	// free the memory we used for the buffer
	

Open in new window

What I would do is take the first part of the main function (where you read the csv file) and make it a function.
It should take a filename, an array of DATATYPES, and a number that says how many structs are in the array.
When you load the initial file, send it a 0.
This way you can add them starting from that place (start i at that number)
That way, you just call that function and send it the new file and it will add them to the end.

Your *read DIRECTORY file into memory* code doesn't do anything right now. You just need to take your INDEX array and put it into a file and be able to load it again. You could use a binary file or anything else that you please (I wouldn't use csv since you would have to do all the tok stuff).
Avatar of crazy4s

ASKER

i'm not sure what should i put the one that are in bold
and then in my main should i open DATABASE in "a"?

void addFile()
{
	DATATYPE Struct2;	// datatype struct
	DATATYPE Array2[300]; // datatype array for a lot of them
	
	if((FI = fopen([b]"AC1.txt"[/b], "r")) == NULL) // [b]I'm not sure what should i put at "AC1.txt" as i want it to [/b]
    		err_sys("Open Fail\n");                 // [b]be the user input filename when they choose option 1[/b]

	while ( fgets( (char *) Line,1000,FI) != NULL) // fill buffer up to newline or eof or error
    	{

	Tok = strtok( Line ,",\n"); 	// skip ID number

        Tok = strtok( NULL ,",\n"); 	// this should get the country code 
        Struct2.code[0] = Tok[0];
        Struct2.code[1] = Tok[1];
        Struct2.code[2] = Tok[2];
        Struct2.code[3] = 0; 	// To create "string" 

	Tok = strtok( NULL ,",\n"); 	// this should get the country name 
        strncpy(&Struct2.name[0],Tok,50);	// copy string at most 50 chars

	Tok = strtok( NULL ,",\n"); 	// skip
	Tok = strtok( NULL ,",\n"); 	// skip 
	Tok = strtok( NULL ,",\n"); 	// skip
	Tok = strtok( NULL ,",\n"); 	// skip 

	Tok = strtok( NULL ,",\n"); 	// this should get the population
	Struct2.pop = atoi(Tok);	// convert string to integer

        Tok = strtok( NULL ,",\n"); 	// this one should get life expectancy
        Struct2.life_expectancy = atof(Tok);	// convert string to a floating point number

[b]	strcpy(Array2[i].code,Struct2.code);	// get the current code 
	strcpy(Array2[i].name,Struct2.name);	// get the current name
	Array2[i].pop = Struct2.pop;		// get the current population
	Array2[i].life_expectancy = Struct2.life_expectancy; // get the current life expectancy

	strcpy(StructArray[i].code, ActualStruct.code);	// get the current code 
	StructArray[i].offset = ftell(FO);             	// get the current offset in the DATABASE file [/b]

	if (fwrite(&Array2[i], sizeof(DATATYPE),1,FO) != 1)  // write into database
		err_sys("fwrite error");

	i++;
	size = i;
	}
}

Open in new window

Avatar of crazy4s

ASKER

>>When you load the initial file, send it a 0.
yes i know i should load the new file into the last position on the existing file? but i don't understand send it a 0 meant here?
Not quite what I meant.
Declare the array in main and pass it to the function. Also pass the current number of items in the array (in the initial run this is 0).
Then start i at this number
so it would look something like
void addFile(DATATYPE* Array2, char* filename, int startHere)
{
    int i = startHere;
    //rest of code. DO NOT re-declare Array2 (i.e. remove your line 4)
if((FI = fopen(filename, "r")) == NULL) //etc, etc
Avatar of crazy4s

ASKER

>>Declare the array in main and pass it to the function
not really understand.. but do you meant i've to put DATATYPE Array[300] inside the main func?
but this is the user option right? doesn't that means when the user choose option 1 the prog will not run back to the main but to the addFile func?
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of crazy4s

ASKER

do you meant like that?
int addFile(DATATYPE* Array2, char* filename, int startHere)
{
	DATATYPE Struct2;	
	int i = startHere;	
	if((FI = fopen(filename, "r")) == NULL) // open a stream from "countries"
    		err_sys("Open Fail\n");

	while ( fgets( (char *) Line,1000,FI) != NULL) // fill buffer up to newline or eof or error
    	{

	Tok = strtok( Line ,",\n"); 	// skip ID number

        Tok = strtok( NULL ,",\n"); 	// this should get the country code 
        Struct2.code[0] = Tok[0];
        Struct2.code[1] = Tok[1];
        Struct2.code[2] = Tok[2];
        Struct2.code[3] = 0; 	// To create "string" 

	Tok = strtok( NULL ,",\n"); 	// this should get the country name 
        strncpy(&Struct2.name[0],Tok,50);	// copy string at most 50 chars

	Tok = strtok( NULL ,",\n"); 	// skip
	Tok = strtok( NULL ,",\n"); 	// skip 
	Tok = strtok( NULL ,",\n"); 	// skip
	Tok = strtok( NULL ,",\n"); 	// skip 

	Tok = strtok( NULL ,",\n"); 	// this should get the population
	Struct2.pop = atoi(Tok);	// convert string to integer

        Tok = strtok( NULL ,",\n"); 	// this one should get life expectancy
        Struct2.life_expectancy = atof(Tok);	// convert string to a floating point number

	strcpy(Array2[i].code,Struct2.code);	// get the current code 
	strcpy(Array2[i].name,Struct2.name);	// get the current name
	Array2[i].pop = Struct2.pop;		// get the current population
	Array2[i].life_expectancy = Struct2.life_expectancy; // get the current life expectancy

	strcpy(StructArray[i].code, ActualStruct.code);	// get the current code 
	StructArray[i].offset = ftell(FO);             	// get the current offset in the DATABASE file 

	if (fwrite(&Array2[i], sizeof(DATATYPE),1,FO) != 1)  // write the struct to the DATABASE file 
		err_sys("fwrite error");

	i++;
	return i;
	}
}
/***************************Main Function********************************************/

int main() 
{ 
  	DATATYPE DatabaseArray[300];
  	char userfile[50];
  	int count = 0;
	int i = 0;
	int size = 0;
	FILE *FI, *FO, *FO2;
	char Line[1000];  // NO input line (delimited by \n) is longer than 1000

	char * Tok;         // token from line

	count = AddFile(DatabaseArray,"AC1.txt",0);
	
	if((FI = fopen("AC1.txt", "r")) == NULL) // open a stream from "countries"
    		err_sys("Open Fail\n");

	if((FO = fopen("DATABASE.txt", "wb")) == NULL) // open a stream from "countries"
    		err_sys("Open DATABASE Fail\n");

	if((FO2 = fopen("DIRECTORY.txt", "w+")) == NULL) // open a stream from "countries"
    		err_sys("Open DIRECTORY Fail\n");

    while ( fgets( (char *) Line,1000,FI) != NULL) // fill buffer up to newline or eof or error
    {

	Tok = strtok( Line ,",\n"); 	// skip ID number

        Tok = strtok( NULL ,",\n"); 	// this should get the country code 
        ActualStruct.code[0] = Tok[0];
        ActualStruct.code[1] = Tok[1];
        ActualStruct.code[2] = Tok[2];
        ActualStruct.code[3] = 0; 	// To create "string" 

	Tok = strtok( NULL ,",\n"); 	// this should get the country name 
        strncpy(&ActualStruct.name[0],Tok,50);	// copy string at most 50 chars

	Tok = strtok( NULL ,",\n"); 	// skip
	Tok = strtok( NULL ,",\n"); 	// skip 
	Tok = strtok( NULL ,",\n"); 	// skip
	Tok = strtok( NULL ,",\n"); 	// skip 

	Tok = strtok( NULL ,",\n"); 	// this should get the population
	ActualStruct.pop = atoi(Tok);	// convert string to integer

        Tok = strtok( NULL ,",\n"); 	// this one should get life expectancy
        ActualStruct.life_expectancy = atof(Tok);	// convert string to a floating point number

	strcpy(DatabaseArray[i].code,ActualStruct.code);	// get the current code 
	strcpy(DatabaseArray[i].name,ActualStruct.name);	// get the current name
	DatabaseArray[i].pop = ActualStruct.pop;		// get the current population
	DatabaseArray[i].life_expectancy = ActualStruct.life_expectancy; // get the current life expectancy

	strcpy(StructArray[i].code, ActualStruct.code);	// get the current code 
	StructArray[i].offset = ftell(FO);             	// get the current offset in the DATABASE file 

	if (fwrite(&DatabaseArray[i], sizeof(DATATYPE),1,FO) != 1)  // write the struct to the DATABASE file 
		err_sys("fwrite error");

	i++;
	size = i;
	}

/****************************Sort the array and write into DIRECTORY*****************************/

	sort(StructArray,size);	// call sort function
	
	for (i=0; i<size; i++)
	{	
		if (fwrite(&StructArray[i], sizeof(INDEX),1,FO2) != 1)  // write the struct to the DIRECTORY file 
			err_sys("fwrite error");
	}

	if (fclose(FI))				// close file descriptor FI
		err_sys("Close error\n");	
	if (fclose(FO))				// close file descriptor FO
		err_sys("Close error\n");	
	if (fclose(FO2))			// close file descriptor FO2
		err_sys("Close error\n");
	
/*********************************************MENU************************************************/

	int c = -1;
	while( c != 4)
	{
		printf("Please select an option (1 to 4):\n");
		printf("1. Add to the DATABASE\n");
		printf("2. Search the DATABASE\n");
		printf("3. List all the countries in DATABASE by ordered Country Code\n");
		printf("4. Press q to exit\n");
		fflush(stdin);
		c = -1;		// error value if scanf fails
		scanf("%d", &c);
		switch (c)
		{
			case 1:
                                printf("Filename(data that you would like to add in): ");
				scanf("%s",&userfile);
				count = AddFile(DatabaseArray, userfile, count)
				break;
			case 2:
				search(size);
				break;
			case 3: 
				printsort(size);
				break;
			case 4:
				puts("Exiting program!");
				return 0;
			default:
				printf("\nNot implemented yet!");
		}
	}
}

Open in new window


and them I'm not sure what should i put here do we do the same thing to the INDEX array like we did for the first time or?
this is the lower part of the AddFile func
strcpy(StructArray[i].code, ActualStruct.code);	// get the current code 
	StructArray[i].offset = ftell(FO);             	// get the current offset in the DATABASE file 

	if (fwrite(&Array2[i], sizeof(DATATYPE),1,FO) != 1)  // write the struct to the DATABASE file 
		err_sys("fwrite error");

	i++;
        size = i: // do i still need this to calculate for the size too?
	return i;
	}

Open in new window

Avatar of crazy4s

ASKER

hmm it should be something like this
int addFile(DATATYPE* Array2, char* filename, int startHere)
{
	DATATYPE Struct2;	
	int i = startHere;	
	int size = startHere;
	FILE *FI *FO;
	char Line[1000];  // NO input line (delimited by \n) is longer than 1000

	char * Tok; 	
	if((FI = fopen(filename, "r")) == NULL) // open a stream from "countries"
    		err_sys("Open Fail\n");

	if((FO = fopen("DATABASE.txt", "a")) == NULL) // open a stream from "countries"
    		err_sys("Open DATABASE Fail\n");

	while ( fgets( (char *) Line,1000,FI) != NULL) // fill buffer up to newline or eof or error
    	{

	Tok = strtok( Line ,",\n"); 	// skip ID number

        Tok = strtok( NULL ,",\n"); 	// this should get the country code 
        Struct2.code[0] = Tok[0];
        Struct2.code[1] = Tok[1];
        Struct2.code[2] = Tok[2];
        Struct2.code[3] = 0; 	// To create "string" 

	Tok = strtok( NULL ,",\n"); 	// this should get the country name 
        strncpy(&Struct2.name[0],Tok,50);	// copy string at most 50 chars

	Tok = strtok( NULL ,",\n"); 	// skip
	Tok = strtok( NULL ,",\n"); 	// skip 
	Tok = strtok( NULL ,",\n"); 	// skip
	Tok = strtok( NULL ,",\n"); 	// skip 

	Tok = strtok( NULL ,",\n"); 	// this should get the population
	Struct2.pop = atoi(Tok);	// convert string to integer

        Tok = strtok( NULL ,",\n"); 	// this one should get life expectancy
        Struct2.life_expectancy = atof(Tok);	// convert string to a floating point number

	strcpy(Array2[i].code,Struct2.code);	// get the current code 
	strcpy(Array2[i].name,Struct2.name);	// get the current name
	Array2[i].pop = Struct2.pop;		// get the current population
	Array2[i].life_expectancy = Struct2.life_expectancy; // get the current life expectancy

	strcpy(StructArray[i].code, ActualStruct.code);	// get the current code 
	StructArray[i].offset = ftell(FO);             	// get the current offset in the DATABASE file 

	if (fwrite(&Array2[i], sizeof(DATATYPE),1,FO) != 1)  // write the struct to the DATABASE file 
		err_sys("fwrite error");

	i++;
	return i;
	}

	if (fclose(FI))				// close file descriptor FI
		err_sys("Close error\n");	
	if (fclose(FO))				// close file descriptor FO
		err_sys("Close error\n");

}
/***************************Main Function********************************************/

int main() 
{ 
  	DATATYPE DatabaseArray[300];
  	char userfile[50];
  	int count = 0;
	int i = 0;
	int size = 0;
	FILE *FI, *FO, *FO2;
	char Line[1000];  // NO input line (delimited by \n) is longer than 1000

	char * Tok;         // token from line

	count = AddFile(DatabaseArray,"AC1.txt",0);
	
	if((FI = fopen("AC1.txt", "r")) == NULL) // open a stream from "countries"
    		err_sys("Open Fail\n");

	if((FO = fopen("DATABASE.txt", "wb")) == NULL) // open a stream from "countries"
    		err_sys("Open DATABASE Fail\n");

	if((FO2 = fopen("DIRECTORY.txt", "w+")) == NULL) // open a stream from "countries"
    		err_sys("Open DIRECTORY Fail\n");

    while ( fgets( (char *) Line,1000,FI) != NULL) // fill buffer up to newline or eof or error
    {

	Tok = strtok( Line ,",\n"); 	// skip ID number

        Tok = strtok( NULL ,",\n"); 	// this should get the country code 
        ActualStruct.code[0] = Tok[0];
        ActualStruct.code[1] = Tok[1];
        ActualStruct.code[2] = Tok[2];
        ActualStruct.code[3] = 0; 	// To create "string" 

	Tok = strtok( NULL ,",\n"); 	// this should get the country name 
        strncpy(&ActualStruct.name[0],Tok,50);	// copy string at most 50 chars

	Tok = strtok( NULL ,",\n"); 	// skip
	Tok = strtok( NULL ,",\n"); 	// skip 
	Tok = strtok( NULL ,",\n"); 	// skip
	Tok = strtok( NULL ,",\n"); 	// skip 

	Tok = strtok( NULL ,",\n"); 	// this should get the population
	ActualStruct.pop = atoi(Tok);	// convert string to integer

        Tok = strtok( NULL ,",\n"); 	// this one should get life expectancy
        ActualStruct.life_expectancy = atof(Tok);	// convert string to a floating point number

	strcpy(DatabaseArray[i].code,ActualStruct.code);	// get the current code 
	strcpy(DatabaseArray[i].name,ActualStruct.name);	// get the current name
	DatabaseArray[i].pop = ActualStruct.pop;		// get the current population
	DatabaseArray[i].life_expectancy = ActualStruct.life_expectancy; // get the current life expectancy

	strcpy(StructArray[i].code, ActualStruct.code);	// get the current code 
	StructArray[i].offset = ftell(FO);             	// get the current offset in the DATABASE file 

	if (fwrite(&DatabaseArray[i], sizeof(DATATYPE),1,FO) != 1)  // write the struct to the DATABASE file 
		err_sys("fwrite error");

	i++;
	size = i;
	}

/****************************Sort the array and write into DIRECTORY*****************************/

	sort(StructArray,size);	// call sort function
	
	for (i=0; i<size; i++)
	{	
		if (fwrite(&StructArray[i], sizeof(INDEX),1,FO2) != 1)  // write the struct to the DIRECTORY file 
			err_sys("fwrite error");
	}

	if (fclose(FI))				// close file descriptor FI
		err_sys("Close error\n");	
	if (fclose(FO))				// close file descriptor FO
		err_sys("Close error\n");	
	if (fclose(FO2))			// close file descriptor FO2
		err_sys("Close error\n");
	
/*********************************************MENU************************************************/

	int c = -1;
	while( c != 4)
	{
		printf("Please select an option (1 to 4):\n");
		printf("1. Add to the DATABASE\n");
		printf("2. Search the DATABASE\n");
		printf("3. List all the countries in DATABASE by ordered Country Code\n");
		printf("4. Press q to exit\n");
		fflush(stdin);
		c = -1;		// error value if scanf fails
		scanf("%d", &c);
		switch (c)
		{
			case 1:
                                printf("Filename(data that you would like to add in): ");
				scanf("%s",&userfile);
				count = AddFile(DatabaseArray, userfile, count)
				break;
			case 2:
				search(size);
				break;
			case 3: 
				printsort(size);
				break;
			case 4:
				puts("Exiting program!");
				return 0;
			default:
				printf("\nNot implemented yet!");
		}
	}
}

Open in new window

Avatar of crazy4s

ASKER

hmmm there was no error but i can't run the prog
/****************************Add File***********************************************/

int addFile(DATATYPE* Array2, char* filename, int startHere)
{
	DATATYPE Struct2;	
	int i = startHere;	
	int size = startHere;
	FILE *FI, *FO;
	char Line[1000];  // NO input line (delimited by \n) is longer than 1000

	char * Tok; 	
	if((FI = fopen(filename, "r")) == NULL) // open a stream from "countries"
    		err_sys("Open Fail\n");

	if((FO = fopen("DATABASE.txt", "a")) == NULL) // open a stream from "countries"
    		err_sys("Open DATABASE Fail\n");

	while ( fgets( (char *) Line,1000,FI) != NULL) // fill buffer up to newline or eof or error
    	{

	Tok = strtok( Line ,",\n"); 	// skip ID number

        Tok = strtok( NULL ,",\n"); 	// this should get the country code 
        Struct2.code[0] = Tok[0];
        Struct2.code[1] = Tok[1];
        Struct2.code[2] = Tok[2];
        Struct2.code[3] = 0; 	// To create "string" 

	Tok = strtok( NULL ,",\n"); 	// this should get the country name 
        strncpy(&Struct2.name[0],Tok,50);	// copy string at most 50 chars

	Tok = strtok( NULL ,",\n"); 	// skip
	Tok = strtok( NULL ,",\n"); 	// skip 
	Tok = strtok( NULL ,",\n"); 	// skip
	Tok = strtok( NULL ,",\n"); 	// skip 

	Tok = strtok( NULL ,",\n"); 	// this should get the population
	Struct2.pop = atoi(Tok);	// convert string to integer

        Tok = strtok( NULL ,",\n"); 	// this one should get life expectancy
        Struct2.life_expectancy = atof(Tok);	// convert string to a floating point number

	strcpy(Array2[i].code,Struct2.code);	// get the current code 
	strcpy(Array2[i].name,Struct2.name);	// get the current name
	Array2[i].pop = Struct2.pop;		// get the current population
	Array2[i].life_expectancy = Struct2.life_expectancy; // get the current life expectancy

	strcpy(StructArray[i].code, Struct2.code);	// get the current code 
	StructArray[i].offset = ftell(FO);             	// get the current offset in the DATABASE file 

	if (fwrite(&Array2[i], sizeof(DATATYPE),1,FO) != 1)  // write the struct to the DATABASE file 
		err_sys("fwrite error");

	i++;
	return i;
	}

	if (fclose(FI))				// close file descriptor FI
		err_sys("Close error\n");	
	if (fclose(FO))				// close file descriptor FO
		err_sys("Close error\n");

}
/***************************Main Function********************************************/

int main() 
{ 
  	DATATYPE DatabaseArray[300];
  	char userfile[50];
  	int count = 0;
	int i = 0;
	int size = 0;
	FILE *FI, *FO, *FO2;
	char Line[1000];  // NO input line (delimited by \n) is longer than 1000

	char * Tok;         // token from line

	count = AddFile(DatabaseArray,"AC1.txt",0);
	
	if((FI = fopen("AC1.txt", "r")) == NULL) // open a stream from "countries"
    		err_sys("Open Fail\n");

	if((FO = fopen("DATABASE.txt", "wb")) == NULL) // open a stream from "countries"
    		err_sys("Open DATABASE Fail\n");

	if((FO2 = fopen("DIRECTORY.txt", "w+")) == NULL) // open a stream from "countries"
    		err_sys("Open DIRECTORY Fail\n");

    while ( fgets( (char *) Line,1000,FI) != NULL) // fill buffer up to newline or eof or error
    {

	Tok = strtok( Line ,",\n"); 	// skip ID number

        Tok = strtok( NULL ,",\n"); 	// this should get the country code 
        ActualStruct.code[0] = Tok[0];
        ActualStruct.code[1] = Tok[1];
        ActualStruct.code[2] = Tok[2];
        ActualStruct.code[3] = 0; 	// To create "string" 

	Tok = strtok( NULL ,",\n"); 	// this should get the country name 
        strncpy(&ActualStruct.name[0],Tok,50);	// copy string at most 50 chars

	Tok = strtok( NULL ,",\n"); 	// skip
	Tok = strtok( NULL ,",\n"); 	// skip 
	Tok = strtok( NULL ,",\n"); 	// skip
	Tok = strtok( NULL ,",\n"); 	// skip 

	Tok = strtok( NULL ,",\n"); 	// this should get the population
	ActualStruct.pop = atoi(Tok);	// convert string to integer

        Tok = strtok( NULL ,",\n"); 	// this one should get life expectancy
        ActualStruct.life_expectancy = atof(Tok);	// convert string to a floating point number

	strcpy(DatabaseArray[i].code,ActualStruct.code);	// get the current code 
	strcpy(DatabaseArray[i].name,ActualStruct.name);	// get the current name
	DatabaseArray[i].pop = ActualStruct.pop;		// get the current population
	DatabaseArray[i].life_expectancy = ActualStruct.life_expectancy; // get the current life expectancy

	strcpy(StructArray[i].code, ActualStruct.code);	// get the current code 
	StructArray[i].offset = ftell(FO);             	// get the current offset in the DATABASE file 

	if (fwrite(&DatabaseArray[i], sizeof(DATATYPE),1,FO) != 1)  // write the struct to the DATABASE file 
		err_sys("fwrite error");

	i++;
	size = i;
	}

/****************************Sort the array and write into DIRECTORY*****************************/

	sort(StructArray,size);	// call sort function
	
	for (i=0; i<size; i++)
	{	
		if (fwrite(&StructArray[i], sizeof(INDEX),1,FO2) != 1)  // write the struct to the DIRECTORY file 
			err_sys("fwrite error");
	}

	if (fclose(FI))				// close file descriptor FI
		err_sys("Close error\n");	
	if (fclose(FO))				// close file descriptor FO
		err_sys("Close error\n");	
	if (fclose(FO2))			// close file descriptor FO2
		err_sys("Close error\n");

/*********************************************MENU************************************************/

	int c = -1;
	while( c != 4)
	{
		printf("Please select an option (1 to 4):\n");
		printf("1. Add to the DATABASE\n");
		printf("2. Search the DATABASE\n");
		printf("3. List all the countries in DATABASE by ordered Country Code\n");
		printf("4. Press q to exit\n");
		fflush(stdin);
		c = -1;		// error value if scanf fails
		scanf("%d", &c);
		switch (c)
		{
			case 1:
                                printf("Filename(data that you would like to add in): ");
				scanf("%s",&userfile);
				count = AddFile(DatabaseArray, userfile, count);
				break;
			case 2:
				search(size);
				break;
			case 3: 
				printsort(size);
				break;
			case 4:
				puts("Exiting program!");
				return 0;
			default:
				printf("\nNot implemented yet!");
		}
	}
}

Open in new window


and the prob seems to be in the addFile func
Undefined                       first referenced
 symbol                             in file
AddFile                             /tmp/cczLEx5O.o
ld: fatal: Symbol referencing errors. No output written to MY
collect2: ld returned 1 exit status

any help will be greatly appreciated!

Avatar of crazy4s

ASKER

hmm no wait... you said to take the first part of the main func and make it a func is it meant that this part is no more longer in the main func?
I see you accepted a solution. I trust that means you got it working? Sorry that I dropped out of the conversation. My wife went into labor and I haven't been on here since Tuesday.
Avatar of crazy4s

ASKER

no is still not working can you help me?
Avatar of crazy4s

ASKER

btw thanks i've already figured out the errors!
I see you've opened another question, so I trust you'll get the help you need there. Phoffric is very knowledgeable. In the future, if you hit the 'ask a related question' link it will notify everyone in that question that the new question is there. It will also link them so that it's easer for all the experts in the new question to figure everything out more quickly.