Solved

random access file

Posted on 2011-02-17
46
784 Views
Last Modified: 2012-05-11
I was asked to read a CSV file line by line and then create a structs for just 4 fields. Then I've to write the struct into a binary file at some offset. And now write out pairs of values(Country Code, Offset) pairs into a second file which can known as an Index file and I have to be able to sort and search by country code.
This is what I have so far but I'm really confused how do I fwrite only the country code and the offset into the index file.
Thanks for the help in advance.

the original text file is something like that:
115,DZA,Algeria,Africa,Northern Africa,2381741,1962,31471000,69.7,49982
146,AGO,Angola,Africa,Central Africa,1246700,1975,12878000,38.3,6648
.
.
.

#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];		
		int offset;		// offset of the data
	} INDEX;


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

void addIndex(INDEX *index)
{
	INDEX record;
	FILE *fp;
	if((fp=fopen("DIRECTORY.txt","ab")) != NULL)
	{
		fwrite(index, sizeof(INDEX),1,fp);
		fclose(fp);
	}
}

void addIndexData(char code, int offset)
{
	INDEX index = {code, offset};
	addIndex(&index);
}

void showIndex(INDEX *index)
{
	printf("%s -> %d\n", index->code, index->offset);
}

void showFile()
{
	FILE *fp;
	if ((fp=fopen("DIRECTORY.txt", "rb")) != NULL)
	{
		size_t itemSize = sizeof(INDEX);
		INDEX item;
		fread(&item,1,itemSize,fp);
		while(!feof(fp))
		{
			showIndex(&item);
			fread(&item,1,itemSize,fp);
		}
		fclose(fp);
	}
}

void sortFile()
{
	FILE *fp;
	if ((fp=fopen("DIRECTORY.txt","rb+")) != NULL)
	{
		size_t itemSize = sizeof(INDEX);
		INDEX data1, data2;
		int flag = 1;
		
		// bubble sort
		while (flag)
		{
			flag = 0;
			fread(&data1, itemSize, 1, fp);
			fread(&data2, itemSize, 1, fp);
			while (!feof(fp))
			{
				if (strcmp(data2.code, data1.code) < 0)	
				{
					fseek(fp,(itemSize * -2), SEEK_CUR);
					fwrite(&data2, itemSize, 1, fp);
					fwrite(&data1, itemSize, 1, fp);
					flag = 1;
				}
				else
				{
					data1 = data2;
				}
				fread(&data2, itemSize, 1, fp);
			}
			if (flag)
			{
				rewind(fp);
			}
		}
		fclose(fp);
	}
}
				

int main() 
{ 

	//int m, size;
	int ndx;
	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("AllCountries1.txt", "r")) == NULL) // open a stream from "countries"
    		err_sys("Open Fail\n");

	if((FO = fopen("DATABASE.txt", "wb")) == NULL) // create a file called DATABASE
    		err_sys("Open DATABASE Fail\n");

	if((FO2 = fopen("DIRECTORY.txt", "w+")) == NULL) //create a file like an INDEX
    		err_sys("Open DIRECTORY Fail\n");

    while ( fgets( (char *) Line,1000,FI) != NULL) // fill buffer up to newline 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);

	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);

        Tok = strtok( NULL ,",\n"); 	// this one should get life expectancy
        ActualStruct.life_expectancy = atof(Tok);


	if (fwrite(&ActualStruct, sizeof(DATATYPE),1,FO) != 1)
		err_sys("fwrite error");

	if (fwrite(&ActualStruct.code, sizeof(DATATYPE),1,FO2) != 1)
		err_sys("fwrite error");

	printf("%5s%50s%15u%18f\n",&ActualStruct.code[0],&ActualStruct.name[0],ActualStruct.pop,ActualStruct.life_expectancy);

	}
	
	printf("Before Sort:\n");
	showFile();

	sortFile();
	printf("After Sort:\n");
	showFile();

    	if (ferror(FI)) 
		err_sys("error in reading \n"); // and now output this for error 
	if (fclose(FI))
		err_sys("Close error\n");	
	if (fclose(FO))
		err_sys("Close error\n");
    	printf(" Made the break \n");  // and this if not error :) 

}

Open in new window

0
Comment
Question by:crazy4s
  • 26
  • 20
46 Comments
 
LVL 53

Accepted Solution

by:
Infinity08 earned 500 total points
ID: 34914733
>> This is what I have so far but I'm really confused how do I fwrite only the country code and the offset into the index file.

Do you mean something like the code below ?

Note that it makes use of ftell to get the position in the file :

        http://www.cplusplus.com/reference/clibrary/cstdio/ftell/

And you can subsequently use fseek to seek to that position in the file :

        http://www.cplusplus.com/reference/clibrary/cstdio/fseek/


Note that if you want the indexes to be sorted in the DIRECTORY file, you could eg. build the index array in memory, sort it, and then write the whole array into the file.
typedef struct {
	char code[4];		
	long int offset;                                /* make this a long int */
} INDEX;


/* <SNIP> */


INDEX index = { 0 };
strcpy(index.code, ActualStruct.code);                  /* get the current code */
index.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");

if (fwrite(&index, sizeof(INDEX), 1, FO2) != 1)         /* write the index to the DIRECTORY file */
	err_sys("fwrite error");

Open in new window

0
 

Author Comment

by:crazy4s
ID: 34914786
sorry but did you meant all this code is in the while loop of the main function?
yes I know I've to build that index array into memory but I got no idea how should i do it?
any help would be appreciate:)

INDEX index = { 0 };
strcpy(index.code, ActualStruct.code);                  /* get the current code */
index.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");

if (fwrite(&index, sizeof(INDEX), 1, FO2) != 1)         /* write the index to the DIRECTORY file */
	err_sys("fwrite error");

Open in new window

0
 
LVL 53

Expert Comment

by:Infinity08
ID: 34914873
>> sorry but did you meant all this code is in the while loop of the main function?

The part you quoted, yes. It replaces the two fwrite's you have there now. Do you see what's happening ? If not, please ask for clarification.


>> yes I know I've to build that index array into memory but I got no idea how should i do it?

Well, the first three lines in the code you quoted fill one INDEX struct with the right values for the current database entry. You can do that inside the loop for every entry you add to the DATABASE file. Make sure to put all these INDEX structs into some container (I see that you have an array for that purpose right now).

When the loop has ended, you can sort the container, and then write the entire container to the DIRECTORY file.
0
 

Author Comment

by:crazy4s
ID: 34914953
let me confirm 1 thing first:
this 1 is to write the country code and the offset into the directory file, am i right?
if (fwrite(&index, sizeof(INDEX), 1, FO2) != 1)         /* write the index to the DIRECTORY file */
	err_sys("fwrite error");

Open in new window



ok and now this will how my while loop looks like, am i  right?
so it means that when it go through every line it will write the struct into the binary and at the same time it write into the index file?
the container you meant is it the addIndex function?
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);

	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);

        Tok = strtok( NULL ,",\n"); 	// this one should get life expectancy
        ActualStruct.life_expectancy = atof(Tok);

	INDEX index = {0};
	strcpy (index.code, ActualStruct.code);		// get the current code
	index.offset = ftell(FO);			// get the current offset in the DATABASE file

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

	if (fwrite(&index, sizeof(INDEX),1,FO2) != 1)			// write the struct into DIRECTORY file
		err_sys("fwrite error");

	printf("%5s%50s%15u%18f\n",&ActualStruct.code[0],&ActualStruct.name[0],ActualStruct.pop,ActualStruct.life_expectancy);

	}

Open in new window


sorry I'm a abit slow in understanding stuffs:)
0
 

Author Comment

by:crazy4s
ID: 34915284
how do I put the INDEX structs from the main function into an array and put into the memory?
AND how do i write back the whole array into the directory file?
Can you explain in more detail?
Thanks.

void addIndex(INDEX *index)
{
	FILE *fp;
	if((fp=fopen("DIRECTORY.txt","ab")) != NULL)
	{
		fwrite(index, sizeof(INDEX),1,fp);
		fclose(fp);
	}
}

void addIndexData(char code, int offset)
{
	INDEX index = {code, offset};
	addIndex(&index);
}

Open in new window

0
 
LVL 53

Assisted Solution

by:Infinity08
Infinity08 earned 500 total points
ID: 34915531
>> this 1 is to write the country code and the offset into the directory file, am i right?

That is correct.


>> ok and now this will how my while loop looks like, am i  right?

If the indexes don't need to be sorted first, that looks good, yes. (don't forget to change the INDEX struct definition to have offset as a long int instead of an int though)


>> so it means that when it go through every line it will write the struct into the binary and at the same time it write into the index file?

Correct.


>> the container you meant is it the addIndex function?

A container is a data structure in memory that can hold multiple objects. In your original code, you had an array that can hold up to 300 INDEX objects :

>> INDEX StructArray[300]; // for a lot of them

StructArray is a container (array) that holds INDEX objects.


>> sorry I'm a abit slow in understanding stuffs:)

No worries. I'm happy to elaborate on anything you want (related to this question).



>> how do I put the INDEX structs from the main function into an array and put into the memory?

Instead of setting the code and offset members of a local INDEX object, set them directly in the relevant item in the array. For example, to set the INDEX at position i in the array :

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


>> AND how do i write back the whole array into the directory file?

You can use fwrite to write the entire array into the file in one go, or you can iterate over the array and write each INDEX object separately.
0
 

Author Comment

by:crazy4s
ID: 34915601
how if I wanted to sort it when I'm  adding into the index? Is it possible to do that?
SO if i set the code and the offset directly to the array I should also put a for loop inside my while loop like this right? can i get rid this -> INDEX index = {0};?

 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

	INDEX index = {0};
	for (i=0 ; i<300; i++)
	{
	strcpy (StructArray[i].code, ActualStruct.code);		// get the current country 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 into DATABASE file
		err_sys("fwrite error");

	if (fwrite(&index, sizeof(INDEX),1,FO2) != 1)			// write the index into DIRECTORY file
		err_sys("fwrite error");

	printf("%5s%50s%15u%18f%10u\n",&ActualStruct.code[0],&ActualStruct.name[0],ActualStruct.pop,ActualStruct.life_expectancy,index.offset);

	}

Open in new window


Thanks.
0
 

Author Comment

by:crazy4s
ID: 34915623
sorry and the 2nd fwrite will become, right?
	if (fwrite(&StructArray, sizeof(INDEX),1,FO2) != 1)			// write the index into DIRECTORY file
		err_sys("fwrite error");

Open in new window

0
 
LVL 53

Expert Comment

by:Infinity08
ID: 34915680
>> how if I wanted to sort it when I'm  adding into the index? Is it possible to do that?

I would fill the array first (add one for each iteration of the while loop), and then sort the array after the while loop.


>> SO if i set the code and the offset directly to the array I should also put a for loop inside my while loop like this right? can i get rid this -> INDEX index = {0};?

That for loop would overwrite all items in the array with the same index.

Maybe a tutorial on how to use arrays would be useful :

        http://www.cplusplus.com/doc/tutorial/arrays/
0
 

Author Comment

by:crazy4s
ID: 34915742
ah I forget that it is in the while loop, ok so this will what be remain the while loop, am i right?
	INDEX index = {0};
	strcpy (StructArray[i].code, ActualStruct.code);		// get the current country 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 into DATABASE file
		err_sys("fwrite error");

	if (fwrite(&StructArray, sizeof(INDEX),1,FO2) != 1)			// write the index into DIRECTORY file
		err_sys("fwrite error");

Open in new window


about the sorting:
so what I've did earlier is it the one you're saying?
I will call sortfile() after the while loop in the main function.
void sortFile()
{
	FILE *fp;
	if ((fp=fopen("DIRECTORY.txt","rb+")) != NULL)
	{
		size_t itemSize = sizeof(INDEX);
		INDEX data1, data2;
		int flag = 1;
		
		// bubble sort
		while (flag)
		{
			flag = 0;
			fread(&data1, itemSize, 1, fp);
			fread(&data2, itemSize, 1, fp);
			while (!feof(fp))
			{
				if (strcmp(data2.code, data1.code) < 0)	
				{
					fseek(fp,(itemSize * -2), SEEK_CUR);
					fwrite(&data2, itemSize, 1, fp);
					fwrite(&data1, itemSize, 1, fp);
					flag = 1;
				}
				else
				{
					data1 = data2;
				}
				fread(&data2, itemSize, 1, fp);
			}
			if (flag)
			{
				rewind(fp);
			}
		}
		fclose(fp);
	}
}

Open in new window

0
 
LVL 53

Expert Comment

by:Infinity08
ID: 34915775
>> I will call sortfile() after the while loop in the main function.

Ah, so you intend to sort the file.

That works too.

In that case, you can just keep the lines I posted originally in the while loop, and that should write all index entries in the DIRECTORY file. After the while loop, you can then sort that file.
0
 

Author Comment

by:crazy4s
ID: 34915812
so now this is my code
#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;


DATATYPE ActualStruct; // for a single struct
INDEX StructArray[300]; // for a lot of them 
		
void addIndex(INDEX *index)
{
	FILE *fp;
	if((fp=fopen("DIRECTORY.txt","ab")) != NULL)
	{
		fwrite(index, sizeof(INDEX),1,fp);
		fclose(fp);
	}
}

void addIndexData(char code, int offset)
{
	INDEX index = {code, offset};
	addIndex(&index);
}

void showIndex(INDEX *index)
{
	printf("%s -> %d\n", index->code, index->offset);
}

void showFile()
{
	FILE *fp;
	if ((fp=fopen("DIRECTORY.txt", "rb")) != NULL)
	{
		size_t itemSize = sizeof(INDEX);
		INDEX item;
		fread(&item,1,itemSize,fp);
		while(!feof(fp))
		{
			showIndex(&item);
			fread(&item,1,itemSize,fp);
		}
		fclose(fp);
	}
}

void sortFile()
{
	FILE *fp;
	if ((fp=fopen("DIRECTORY.txt","rb+")) != NULL)
	{
		size_t itemSize = sizeof(INDEX);
		INDEX data1, data2;
		int flag = 1;
		
		// bubble sort
		while (flag)
		{
			flag = 0;
			fread(&data1, itemSize, 1, fp);
			fread(&data2, itemSize, 1, fp);
			while (!feof(fp))
			{
				if (strcmp(data2.code, data1.code) < 0)	
				{
					fseek(fp,(itemSize * -2), SEEK_CUR);
					fwrite(&data2, itemSize, 1, fp);
					fwrite(&data1, itemSize, 1, fp);
					flag = 1;
				}
				else
				{
					data1 = data2;
				}
				fread(&data2, itemSize, 1, fp);
			}
			if (flag)
			{
				rewind(fp);
			}
		}
		fclose(fp);
	}
}

		
int main() 
{ 

	//int m, size;
	int i=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("AllCountries1.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");


	printf("--------------------------------------------------------------------------------------------------------\n");
	printf("  CODE \t\t\t COUNTRY NAME \t\t\t   POPULATION      LIFE EXPECTANCY    OFFSET\n");
	printf("--------------------------------------------------------------------------------------------------------\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

	INDEX index = {0};
	strcpy (StructArray[i].code, ActualStruct.code);		// get the current country 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 into DATABASE file
		err_sys("fwrite error");

	if (fwrite(&StructArray[i], sizeof(INDEX),1,FO2) != 1)			// write the index into DIRECTORY file
		err_sys("fwrite error");

	printf("%5s%50s%15u%18f%10u\n",&ActualStruct.code[0],&ActualStruct.name[0],ActualStruct.pop,ActualStruct.life_expectancy,StructArray[i].offset);

	}
	
	
	printf("Before Sort:\n");
	showFile();

	sortFile();
	printf("After Sort:\n");
	showFile();

	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(" Made the break \n");  // and this if not error :) 

}

Open in new window


but my output doesn't show the showfile and sorted file?
--------------------------------------------------------------------------------------------------------
  CODE                   COUNTRY NAME                      POPULATION      LIFE EXPECTANCY    OFFSET
--------------------------------------------------------------------------------------------------------
  DZA                                           Algeria       31471000         69.699997         0
  AGO                                            Angola       12878000         38.299999        64
  BEN                                             Benin        6097000         50.200001       128
  BWA                                          Botswana        1622000         39.299999       192
  IOT                    British Indian Ocean Territory              0          0.000000       256
  BFA                                      Burkina Faso       11937000         46.700001       320
  BDI                                           Burundi        6695000         46.200001       384

Before Sort:
After Sort:
 Made the break
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 34915889
>>       if (fwrite(&StructArray[ i ], sizeof(INDEX),1,FO2) != 1)                  // write the index into DIRECTORY file
>>             err_sys("fwrite error");

You don't need to use the array. Use the code I posted in my first post. It's more straightforward, and less error prone.


>> but my output doesn't show the showfile and sorted file?

Make sure to close the files first, before trying to re-open them.
0
 

Author Comment

by:crazy4s
ID: 34915944
so u meant I can take out the INDEX StructArray[300];?

hmm i don't understand by close files... do u meant i shut down everything and turn it on again and run?
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 34916045
>> so u meant I can take out the INDEX StructArray[300];?

That depends on whether you intend to use it for something else.

What I'm saying is that you shouldn't be making us of the array inside the while loop.


>> hmm i don't understand by close files... do u meant i shut down everything and turn it on again and run?

fclose is used to close a file. You're currently using it in several locations, so I'm sure you know how to use it ;)
0
 

Author Comment

by:crazy4s
ID: 34916095
use for something else? hmm for example?
well I've checked all that I've closed all the file descriptor but i still can't get the sorted output?
#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;


DATATYPE ActualStruct; // for a single struct
		
void addIndex(INDEX *index)
{
	FILE *fp;
	if((fp=fopen("DIRECTORY.txt","ab")) != NULL)
	{
		fwrite(index, sizeof(INDEX),1,fp);
		fclose(fp);
	}
}

void addIndexData(char code, int offset)
{
	INDEX index = {code, offset};
	addIndex(&index);
}

void showIndex(INDEX *index)
{
	printf("%s -> %d\n", index->code, index->offset);
}

void showFile()
{
	FILE *fp;
	if ((fp=fopen("DIRECTORY.txt", "rb")) != NULL)
	{
		size_t itemSize = sizeof(INDEX);
		INDEX item;
		fread(&item,1,itemSize,fp);
		while(!feof(fp))
		{
			showIndex(&item);
			fread(&item,1,itemSize,fp);
		}
		fclose(fp);
	}
}

void sortFile()
{
	FILE *fp;
	if ((fp=fopen("DIRECTORY.txt","rb+")) != NULL)
	{
		size_t itemSize = sizeof(INDEX);
		INDEX data1, data2;
		int flag = 1;
		
		// bubble sort
		while (flag)
		{
			flag = 0;
			fread(&data1, itemSize, 1, fp);
			fread(&data2, itemSize, 1, fp);
			while (!feof(fp))
			{
				if (strcmp(data2.code, data1.code) < 0)	
				{
					fseek(fp,(itemSize * -2), SEEK_CUR);
					fwrite(&data2, itemSize, 1, fp);
					fwrite(&data1, itemSize, 1, fp);
					flag = 1;
				}
				else
				{
					data1 = data2;
				}
				fread(&data2, itemSize, 1, fp);
			}
			if (flag)
			{
				rewind(fp);	// set the position indicator to the beginning of the file
			}
		}
		fclose(fp);			// close file descriptor fp
	}
}

		
int main() 
{ 

	//int m, size;
	int i=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("AllCountries1.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");


	printf("--------------------------------------------------------------------------------------------------------\n");
	printf("  CODE \t\t\t COUNTRY NAME \t\t\t   POPULATION      LIFE EXPECTANCY    OFFSET\n");
	printf("--------------------------------------------------------------------------------------------------------\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

	INDEX index = { 0 };
	strcpy(index.code, ActualStruct.code);                  /* get the current code */
	index.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");

	if (fwrite(&index, sizeof(INDEX), 1, FO2) != 1)         /* write the index to the DIRECTORY file */
		err_sys("fwrite error");

	printf("%5s%50s%15u%18f%10u\n",&ActualStruct.code[0],&ActualStruct.name[0],ActualStruct.pop,ActualStruct.life_expectancy,index.offset);

	}
	
	
	printf("Before Sort:\n");
	showFile();

	sortFile();
	printf("After Sort:\n");
	showFile();

	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(" Made the break \n");  // and this if not error :) 

}

Open in new window

0
 

Author Comment

by:crazy4s
ID: 34916190
previously I've open a file and read it and now i would like to add in another file and continue at the end of the previous Directory file, what should i do?
0
 

Author Comment

by:crazy4s
ID: 34916295
I just realized that the lecturer wants us to include at least the step of using only an internal array for retrieve and demonstrate that we've indeed sorted the structs by country code so is it means that I have to use this INDEX StructArray[300]?
Sorry for asking so many questions:)
Thanks.
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 34917056
>> use for something else? hmm for example?

I don't know. It's your code ;)


>> well I've checked all that I've closed all the file descriptor but i still can't get the sorted output?

You need to close the files BEFORE trying to re-open them. Note that the showFile function tries to open the DIRECTORY file eg. So you need to make sure that the DIRECTORY file is closed BEFORE you call the showFile function.


>> previously I've open a file and read it and now i would like to add in another file and continue at the end of the previous Directory file, what should i do?

Don't know what you mean, but if you want to append new data to an existing file, you can just open the file for appending using the "a" flag. Refer to the fopen reference page for more information :

        http://www.cplusplus.com/reference/clibrary/cstdio/fopen/



>> I just realized that the lecturer wants us to include at least the step of using only an internal array for retrieve and demonstrate that we've indeed sorted the structs by country code so is it means that I have to use this INDEX StructArray[300]?

As I said before : it depends on what you want to do. If you want to sort in memory, then you'll need some kind of container (an array eg.). If you want to sort in the file, then you don't.
0
 

Author Comment

by:crazy4s
ID: 34917221
ah ok so I've moved the fclose before showfile:)
but here comes the problem again, it shows the before sort but it stops at the last data somekind like infinity loop and didn't get to sort file?


--------------------------------------------------------------------------------------------------------
  CODE                   COUNTRY NAME                      POPULATION      LIFE EXPECTANCY    OFFSET
--------------------------------------------------------------------------------------------------------
  DZA                                           Algeria       31471000         69.699997         0
  AGO                                            Angola       12878000         38.299999        64
  BEN                                             Benin        6097000         50.200001       128
  BWA                                          Botswana        1622000         39.299999       192
  IOT                    British Indian Ocean Territory              0          0.000000       256
  BFA                                      Burkina Faso       11937000         46.700001       320
Before Sort:
DZA -> 0
AGO -> 64
BEN -> 128
BWA -> 192
IOT -> 256
BFA -> 320

so if now i want sort in memory, i'll need to use an array INDEX StructArray[300]?
and the codes will change to below, is that all?
	INDEX index = { 0 };
	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");

	if (fwrite(&StructArray[i], sizeof(INDEX), 1, FO2) != 1)         /* write the index to the DIRECTORY file */
		err_sys("fwrite error");

Open in new window

0
 
LVL 53

Expert Comment

by:Infinity08
ID: 34917294
>> but here comes the problem again, it shows the before sort but it stops at the last data somekind like infinity loop and didn't get to sort file?

You'll have to figure out where it's stuck. You can either run the code in the debugger, or you can add print statements to track progress.


>> and the codes will change to below, is that all?

You need to think a bit about what's going on.

Either you write the indexes to the file, or you write them into the array. Which you choose, depends on what you want to do.
But don't mix both approaches.

Also make sure that, if you use the array, that you use it correctly. Please refer to the tutorial I posted earlier to get a better idea of what arrays are, how they work, and how you should use them.
0
 

Author Comment

by:crazy4s
ID: 34917322
how do i run the code in debugger?
can you give some example?
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 34917537
Read the documentation for your IDE ;) I don't know what you use, nor do I know how all IDE's work ...
0
What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

 

Author Comment

by:crazy4s
ID: 34917590
I'm currently using unix but i can confirm the problem is in the sortFile() function, because after showFile() before sort i'm able to printf something.
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 34917654
So, now you'll have to narrow it down to figure out where exactly it goes wrong, and then fix that :)
0
 

Author Comment

by:crazy4s
ID: 34917735
yes i roughly understand how the array works but I'm confused about the difference between sorting in memory using the array and sorting in the file? Does both work the same?
and i can't really find where I goes wrong in the sortFile()
void showFile()
{
	FILE *fp;
	if ((fp=fopen("DIRECTORY.txt", "rb")) != NULL)
	{
		size_t itemSize = sizeof(INDEX);				// size of the objects
		INDEX item;
		fread(&item,1,itemSize,fp);
		while(!feof(fp))
		{
			showIndex(&item);					// go to showIndex
			fread(&item,1,itemSize,fp);
		}
		fclose(fp);
	}
}

void sortFile()
{
	FILE *fp;
	if ((fp=fopen("DIRECTORY.txt","rb+")) != NULL)				//open file for reading and writing
	{
		size_t itemSize = sizeof(INDEX);				// size of the objects
		INDEX data1, data2;
		int flag = 1;
		
		// bubble sort
		while (flag)
		{
			flag = 0;
			fread(&data1, itemSize, 1, fp);
			fread(&data2, itemSize, 1, fp);
			while (!feof(fp))
			{
				if (strcmp(data2.code, data1.code) < 0)		// if data2 is smaller than data1
				{
					fseek(fp,(itemSize * -2), SEEK_CUR);	// The offset is set to the current position 
										// plus the offset bytes
					fwrite(&data2, itemSize, 1, fp);
					fwrite(&data1, itemSize, 1, fp);
					flag = 1;
				}
				else
				{
					data1 = data2;
				}
				fread(&data2, itemSize, 1, fp);
			}
			if (flag)
			{
				rewind(fp);	// set the position indicator to the beginning of the file
			}
		}
		fclose(fp);			// close file descriptor fp
	}
}

Open in new window


Thanks for the help again:)
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 34917796
>> Does both work the same?

Pretty much yes. Just the mechanisms for manipulating the data are different, but the algorithm can be the same.


>> and i can't really find where I goes wrong in the sortFile()

Add more printf statements :) Until you've found the exact line where it goes wrong.
0
 

Author Comment

by:crazy4s
ID: 34917847
add more printf statements? for example?
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 34917870
>>  add more printf statements? for example?

If you see the output of a print statement, then you know that the code got at least that far. If you add them in key locations, you can narrow down to one line where the issue occurs.
0
 

Author Comment

by:crazy4s
ID: 34922604
now in my case I've to write the struct into binary(with offset) and write into an array in memory and sort in memory(using insertion sort) so i've made some changes on my code and also the sort file but it seems to have some error.

#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];
DATATYPE ActualStruct; // for a single struct

void sort(INDEX* SortArray[], int n)
{
	int i, j;
	INDEX temp_code;
	for (i=2;i<n;i++)
	{
		temp_code = SortArray[i].code;
		for (j=i-1;j>=0; j++)
		{
			if(strcmp(SortArray[j].code, temp_code) > 0)
			{
			SortArray[j+1].code = SortArray[j].code;
			}
		}
		SortArray[j+1].code = temp_code;
	}
}	

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("AllCountries1.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");


	printf("--------------------------------------------------------------------------------------------------------\n");
	printf("  CODE \t\t\t COUNTRY NAME \t\t\t   POPULATION      LIFE EXPECTANCY    OFFSET\n");
	printf("--------------------------------------------------------------------------------------------------------\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

	INDEX index = { 0 };
	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");

	printf("%5s%50s%15u%18f%10u\n",&ActualStruct.code[0],&ActualStruct.name[0],ActualStruct.pop,ActualStruct.life_expectancy,StructArray[i].offset);

	}
	

	printf("Before Sort:\n");
	
	sortArray(StructArray,size);
	printf("After Sort:\n");
	printf("%s \t %u\n",StructArray[i].code, StructArray[i].offset);


	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(" Made the break \n");  // and this if not error :) 

}

Open in new window


and here's the error message

test1.c: In function `sort':
test1.c:85: error: request for member `code' in something not a structure or union
test1.c:88: error: request for member `code' in something not a structure or union
test1.c:88: error: incompatible type for argument 2 of `strcmp'
test1.c:90: error: request for member `code' in something not a structure or union
test1.c:90: error: request for member `code' in something not a structure or union
test1.c:93: error: request for member `code' in something not a structure or union

I'm trying to parts by parts now.
any help will be greatly appreciated:)
0
 

Author Comment

by:crazy4s
ID: 34922617
in the array there's only the country code and the offset and will be sorted using the country code.
and there're two things I'm not sure what should be put inside the parenthesis.
1)

        void sort(INDEX* SortArray[], int n)  

2)

      sortArray(StructArray,size);
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 34924092
Since you are putting all indexes in the array instead of in the file, you need to make sure to adjust the index (i) into the array each time you add an index to the array. Otherwise, you'll be overwriting the same item every time.

You'll also need to make sure to keep track of the amount of items that are currently in the array, so you know how many you need to sort.


>>         void sort(INDEX* SortArray[], int n)  

That function would axpect an array of pointers to INDEX objects. But that's not the same as an array of INDEX objects, which is how you defined the array :

>> INDEX StructArray[300];
0
 

Author Comment

by:crazy4s
ID: 34926454
hmm i don't get what you meant to adjust the index(i) into the array each time you add an index to the array, can you explain it more detail or maybe example as it'll be easier to understand for me?  
thank you.
0
 

Author Comment

by:crazy4s
ID: 34926494
so for the 2nd one do you meant I've to defined the array as:
DATATYPE StructArray[300]; referring back to the 1st struct (with 4 fields)?
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 34926608
If i is always 0, then setting a value in StructArray[ i ] will always set it in StructArray[0], so you'll always overwrite the same item in the array.

Please refer to the tutorial on arrays I posted earlier. I'm sure it'll clear several things up for you, and give you a better understanding.
0
 

Author Comment

by:crazy4s
ID: 34926969
ahh so you are saying that because i defined int i = 0; instead of int i so every time it loop it'll keep overwriting the first position, am i right?

I actually understand the arrays but there're times that I dunno how to put that into my program and use it properly.

hmm now back to this -> void sort(INDEX* SortArray[], int n)  
i'm not sure which struct to defined for the array...
should i use DATATYPE StructArray[300]; or INDEX StructArray[300] but I only want the array to read only the country code and the offset and that's what I defined in my INDEX struct?
0
 

Author Comment

by:crazy4s
ID: 34927276
>>That function would axpect an array of pointers to INDEX objects. But that's not the same as an array of INDEX objects, which is how you defined the array :

so do you meant that I shouldn't assign a pointer to INDEX
just like this void sort(INDEX SortArray[], int n)?
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 34927402
>>  ahh so you are saying that because i defined int i = 0; instead of int i so every time it loop it'll keep overwriting the first position, am i right?

You need to initialize i to 0, but you also need to increment it after every addition to the array, or you'll always overwrite the same item in the array.


>> I actually understand the arrays but there're times that I dunno how to put that into my program and use it properly.

You seem to be lacking some basic insight about them though, so I really recommend reading through the tutorial. Even if you think you know enough, you might still learn something :)


>> so do you meant that I shouldn't assign a pointer to INDEX
>> just like this void sort(INDEX SortArray[], int n)?

That's good enough yes.
0
 

Author Comment

by:crazy4s
ID: 34927437
so can i put i++; at the end of the while loop?
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 34927524
>> so can i put i++; at the end of the while loop?

You can :)
0
 

Author Comment

by:crazy4s
ID: 34927552
when i run the prog i received these errors for sortFile()
void sort(INDEX SortArray[], int n)
{
	int i, j;
	INDEX temp_code;
	for (i=2;i<n;i++)
	{
		temp_code = SortArray[i].code;
		for (j=i-1;j>=0; j++)
		{
			if(strcmp(SortArray[j].code, temp_code) > 0)
			{
			SortArray[j+1].code = SortArray[j].code;
			}
		}
		SortArray[j+1].code = temp_code;
	}
}

Open in new window



test1.c: In function `sort':
test1.c:85: error: incompatible types in assignment
test1.c:88: error: incompatible type for argument 2 of `strcmp'
test1.c:90: error: incompatible types in assignment
test1.c:93: error: incompatible types in assignment

what is the problem here? as I've already defined temp_code as part of the struct?
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 34931770
>> what is the problem here? as I've already defined temp_code as part of the struct?

temp_code is an INDEX object, not a char*.


We're getting quite far away from the original question ("how do I fwrite only the country code and the offset into the index file") though. If your original question was answered, please close this question by accepting the answer. If not, please feel free to ask for clarification where needed.

For any additional questions that aren't directly related to the original question, please open a new question.
0
 

Author Comment

by:crazy4s
ID: 34932560
so do you meant that I should put char *temp_code and not INDEX temp_code OR?

but this was part of my questions to be able to fwrite the sorted country code and the offset into directory file, do i still need to open a new question ?

0
 
LVL 53

Expert Comment

by:Infinity08
ID: 34933260
>> so do you meant that I should put char *temp_code and not INDEX temp_code OR?

strcmp needs two char*'s as argument, not a char* and an INDEX.


>> but this was part of my questions to be able to fwrite the sorted country code and the offset into directory file, do i still need to open a new question ?

You're now asking about sorting data, no longer about writing data to the file.
0
 

Author Comment

by:crazy4s
ID: 34933275
ok then I'll cont asking in another new question.
Thanks.
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 34933279
Glad to have been of assistance :)

The reason for keeping separate issues in separate questions, is because that keeps the PAQ database clean, and people looking for solutions will have an easier time finding what they need that way.
0

Featured Post

What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

Join & Write a Comment

One of Google's most recent algorithm changes affecting local searches is entitled "The Pigeon Update." This update has dramatically enhanced search inquires for the keyword "Yelp." Google searches with the word "Yelp" included will now yield Yelp a…
The purpose of this article is to demonstrate how we can use conditional statements using Python.
Viewers will learn how to properly install Eclipse with the necessary JDK, and will take a look at an introductory Java program. Download Eclipse installation zip file: Extract files from zip file: Download and install JDK 8: Open Eclipse and …
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.

757 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

23 Experts available now in Live!

Get 1:1 Help Now