#1
  1. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Dec 2012
    Posts
    5
    Rep Power
    0

    Basic C: Help! I'm looking for guidance for file I/O project!


    Hello everyone. I'm a newbie to computer programming and I was wondering if I could get advice for some ideas I have to expand my program. The following code is for a project I just finished for an introduction to c language. It's an employee database. I was wondering if any of you have ideas for editing strings in the text file, or searching for certain strings in a text file within the program? I may have to do additional studying on new topics but I know the basics. All ideas are welcome!

    Code:
    // Joseph Villanueva's Compe160 Project 2
    // Employee Database
    
    #include <conio.h>
    #include <stdio.h>
    #define name_size 30 // custom definitions to keep array sizes consistent
    #define phone_size 20
    #define email_size 40
    
    void viewAll();   // prototypes for subfunctions
    void newEmployee();
    void rewriteDatabase();
    
    struct employeeInformation  // declaration of structure to be user in all functions
    {
        char firstname[name_size];
        char lastname[name_size];
        char phone[phone_size];
        char email[email_size];
        float hourly_pay;
    };
    
    
    int main(void) // begin function main
    {
        int choice; // variable for user's option
        
    
        printf("\n\n\n\n\n\n\n\n\n\n\n\nThis program is the Employee Database for Villanueva Industries\n");
        printf("\nChoose an option:\n");
        printf("1.  View all employees in the system\n");
        printf("2.  Add new employee information\n");  // prompt
        printf("3.  Rewrite the whole database\n");
        printf("4.  Exit program\n\n");
        printf("Choice:  ");
        
        scanf("%d", &choice);
        
        switch (choice) // switch statement for choice
        {
               
            case 1: // if user chooses 1, call viewAll function
                viewAll();
                break;
                
            case 2: // if user chooses 2, call newEmployee function
                newEmployee();
                break;
                
            case 3: // If user chooses 3, call rewriteDatabase function
                rewriteDatabase();
                break;
                
            case 4: // Choice 4 is to end file 
                printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
                printf("Exiting Employee Database Now.\n");
                break;
                
            default: // error messages for any other choices
                printf("\n\n    ***********************************\n");
                printf("    ***  Error! Please Choose 1-4  ***\n");
                printf("    ***********************************\n");
                main(); // recursively calls itself
                break;
                
         } // end switch structure
         
        
        getch(); // stops window from closing for dev c++
        return 0; // check
    } // end of main
    
    void viewAll() // beginning of viewAll function
    {
        printf("\n\n\n\n\n\n\n\n\n\n\n\n");
        printf("\nYou chose to view all employees\n\n");
        
        struct employeeInformation viewInfo; // initialize viewInfo structure
        
        FILE *pDatabaseFile; // file pointer declared
        
        pDatabaseFile = fopen("Database.txt", "r"); // file pointer uses fopen function to open file in read only mode
        
        if (pDatabaseFile != NULL) // if statement for file opened w/o problems 
        {
            printf("First      Last         Phone Number  Hourly Pay    Email\n");
            printf("----------------------------------------------------------------------\n");
            while( !feof(pDatabaseFile) ) // while statement for not end of file character
            {    
                 // fscanf puts file information in viewInfo structure
                fscanf(pDatabaseFile, "%s %s %s %s %f\n", viewInfo.firstname, viewInfo.lastname, viewInfo.phone, viewInfo.email, &viewInfo.hourly_pay);
                printf("%-10s %-13s %-13s %8.2f  %s \n", viewInfo.firstname, viewInfo.lastname, viewInfo.phone, viewInfo.hourly_pay, viewInfo.email);
                 // prints data from the structure's variables
            }
                  
            fclose(pDatabaseFile); // close file
        }
        
        else // else statement for file not opened/ not existing
        {
            printf("\n\n    ******************************************************\n");
            printf("    ***     Error! There is no existing database.      ***\n");
            printf("    ***  Please choose option 2 or 3 in the main menu  ***\n");
            printf("    ******************************************************\n");
        }
        
        printf("\n\nPress any key to continue to main menu\n\n\n\n\n\n\n\n\n");
        getch();
        
        main(); // calls main
    } // end viewAll function
    
    
    void newEmployee() // beginning on newEmployee function
    {
        printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
        printf("\nYou chose to add a new employee's information\n\n");
        
        struct employeeInformation new; // initalize new structure 
        char answer = 'y'; // initalize variable to 'y' for yes
        FILE *pDatabaseFile; // file pointer declared
        
        pDatabaseFile = fopen("Database.txt", "a"); // file pointer uses fopen function to open file in append mode
        
        if (pDatabaseFile != NULL) // if statement for file opened w/o problems 
        {
            while(answer == 'y') // while statement for if answer is 'y'
            {
                printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
                printf("\nYou chose to add a new employee's information\n\n");        
        
                printf("\n*********************************************************************"); // Warning to users 
                printf("\n*** Please refrain from using Spaces or there will be an error!!! ***\n");
                printf("*** Instead use periods in between words.  For Example: Del.Reyes ***\n");
                printf("*********************************************************************\n");
                
                printf("\nFirst Name: ");              // gets info from user and puts it in new structure variables
                scanf("%s", new.firstname);
                
                printf("Last Name: ");
                scanf("%s", new.lastname);
                
                printf("Phone Number: ");
                scanf("%s", new.phone);
                
                printf("Email Address: ");
                scanf("%s", &new.email);
                
                printf("Hourly Pay: ");
                scanf("%f", &new.hourly_pay);
                
                // fprintf statements to write new structure variables in file
                fprintf(pDatabaseFile, "%s %s %s ", new.firstname, new.lastname, new.phone);  
                fprintf(pDatabaseFile, "%s %f\n", new.email, new.hourly_pay);
                
                printf("\nAre there anymore employees you want to enter? [y/n]\n");
                answer = getch(); // statements to see if user has anymore employees to enter
                
                while(answer != 'n' && answer != 'y') // error message for invalid inputs
                {
                    printf("\nError! Please press y or n.");
                    answer = getch();
                }
                
                
            }
            
            printf("\n\nReturning to Main Menu....\n");
            
            fclose(pDatabaseFile); // close file
        }
        
        else // else statement for file not opened
        {
            printf("\nError. Couldn't open the file\n");
        }
        
        main(); // calls main
    } // end newEmployee function
    
    
    void rewriteDatabase() // begin rewriteDatabase function
    {
        int choice; // variable for if user wants accepts warning message
        char answer = 'y'; // initalize char variable to 'y'
        
        struct employeeInformation database; // initialize database structure
        
        printf("\n\n\n\n\n\n\n\n\n\n\n\n\n");
        printf("\nYou chose to rewrite database\n\n");   // warning prompt to user
        printf("********************************************************************\n");
        printf("*** WARNING THIS WILL OVERWRITE PREVIOUS DATA YOU HAVE ENTERED!  ***\n");
        printf("********************************************************************\n\n\n");
        printf("Enter 1 to continue or 2 to go back to the main menu:   ");
        scanf("%d", &choice);
        
        if(choice == 1) // if choice entered is 1
        {
            FILE *pDatabaseFile; // file pointer declared
        
            pDatabaseFile = fopen("Database.txt", "w");// file pointer uses fopen function to open file in write mode
        
            if (pDatabaseFile != NULL)// if statement for file opened w/o problems 
            {
                while(answer == 'y') // while statement for if answer is 'y'
                {
                    printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
    
                    printf("*********************************************************************");
                    printf("\n*** Please refrain from using Spaces or there will be an error!!! ***\n");
                    printf("*** Instead use periods in between words.  For Example: Del.Reyes ***\n");
                    printf("*********************************************************************\n");
                   
                    printf("\nFirst Name: ");      
                    scanf("%s", database.firstname);
                                                    // gets info from user and puts it in database structure variables
                    printf("Last Name: ");
                    scanf("%s", database.lastname);
                    
                    printf("Phone Number: ");
                    scanf("%s", database.phone);
                    
                    printf("Email Address: ");
                    scanf("%s", database.email);
                    
                    printf("Hourly Pay: ");
                    scanf("%f", &database.hourly_pay);
                    
                    // fprintf statements to write database structure variables in file
                    fprintf(pDatabaseFile, "%s %s %s ", database.firstname, database.lastname, database.phone);
                    fprintf(pDatabaseFile, "%s %f\n", database.email, database.hourly_pay);
                    
                    printf("\nAre there anymore employees you want to enter? [y/n]\n");
                    answer = getch();    // statements to see if user has anymore employees to enter
                    
                    while(answer != 'n' && answer != 'y')   // error message for invalid inputs
                    {
                        printf("\nError! Please press y or n.");
                        answer = getch();
                    } // end while statement
                } // end if statement
            
                printf("Returning to Main Menu....");
            
                fclose(pDatabaseFile); // close file
            }// end if statement
        
            else // else statement for error opening file
            {
                printf("\nError. Couldn't open the file\n");
            } // end else
            
            
            main(); // cal main
            
        } // end if statement
        
        else if(choice == 2) // else if statement if user inputs 2
        {
            main(); // main called
        } // end else if statement
        
        else // else statement for invalid answers
        {
            printf("\n******************************");
            printf("\n*** Error! Invalid Answer! ***");
            printf("\n******************************");
            rewriteDatabase(); // recursively calls rewriteDatabase 
        } // end else statement
    
    } // end rewriteDatabase function
  2. #2
  3. I'm Baaaaaaack!
    Devshed God 1st Plane (5500 - 5999 posts)

    Join Date
    Jul 2003
    Location
    Maryland
    Posts
    5,538
    Rep Power
    243
    Without looking at your code, just based on your text, the first thing you need to realize is that you can't search a 'file' for anything. All computing is done in RAM and registers, so first your file has to be read into RAM, then read, bit by bit (literally) into the registers and then a comparison done. Thus, since you have to read the entire file/database contents into memory prior to any analysis, the strategy which you use to do so can have a huge (multiple order of magnitude) impact on performance. BTW, just because everything runs lickety-split when you are testing with tiny amounts of data doesn't mean your application design is scalable. The operating system will cache your file in RAM for you (if the file is small enough, of course, and today that means anything less than a few gigabytes) so you can see huge 'performance' that is totally illusory.

    The general way that data is accessed in the storage system (e.g., file system) is via indexing. That way you don't need to read all the data into RAM just to find something. Indeed, this exact same 'trick' works in RAM as well. The basic idea is you have a sorted set of keys that are much smaller than the base data and you search the set of keys (index) to find the location of the bit you want. The index is much more likely to be kept in RAM (though not necessarily, really big databases have to have indexed into their indexes!) and by being sorted it isn't necessary to traverse the entire index in order to find the key. Then, with the key is a location in storage of the information you want to retrieve and there are ways to use that location to go directly to the location in the file without having to read the entire file into memory.

    All this seems quite silly when you are talking about a 'database' that is a few megabytes. However, if you go with the requirement of having your entire database in RAM, at some point your application will 'suddenly' drop in performance by 1,000x when RAM has been exhausted and the OS starts to write parts of your data back to disk (Google 'paging'). However, if you want to understand how to work at this level, these concepts are critical.

    Regarding databases, today the general method of accessing the data is to let a third-party set of libraries manage it for you (think MySQL, Postgresql, Sybase, Oracle, SQLServer, etc.). You use the language 'SQL' (which, I believe stands for 'structured query language', but it has been a very long time since I cared) to interact with the database engine. While I think it is a really good idea to build your own database to understand the guts and why certain things behave certain ways, in any sort of production environment you should use whatever commonly available product suits your needs (by studying database theory (get ready for 'tuples' and 'ACID'!) you become better able to evaluate the different database offerings).

    Just about every application of note has some sort of data store element. Sometimes it is 'just' an ini file, sometimes it is a terabyte database accessed over a network. Knowing how things work at this level will almost certainly make you a more valuable programmer.

    My blog, The Fount of Useless Information http://sol-biotech.com/wordpress/
    Free code: http://sol-biotech.com/code/.
    Secure Programming: http://sol-biotech.com/code/SecProgFAQ.html.
    Performance Programming: http://sol-biotech.com/code/PerformanceProgramming.html.
    LinkedIn Profile: http://www.linkedin.com/in/keithoxenrider

    It is not that old programmers are any smarter or code better, it is just that they have made the same stupid mistake so many times that it is second nature to fix it.
    --Me, I just made it up

    The reasonable man adapts himself to the world; the unreasonable one persists in trying to adapt the world to himself. Therefore, all progress depends on the unreasonable man.
    --George Bernard Shaw
  4. #3
  5. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Dec 2012
    Posts
    5
    Rep Power
    0
    Originally Posted by mitakeet
    Without looking at your code, just based on your text, the first thing you need to realize is that you can't search a 'file' for anything. All computing is done in RAM and registers, so first your file has to be read into RAM, then read, bit by bit (literally) into the registers and then a comparison done. Thus, since you have to read the entire file/database contents into memory prior to any analysis, the strategy which you use to do so can have a huge (multiple order of magnitude) impact on performance. BTW, just because everything runs lickety-split when you are testing with tiny amounts of data doesn't mean your application design is scalable. The operating system will cache your file in RAM for you (if the file is small enough, of course, and today that means anything less than a few gigabytes) so you can see huge 'performance' that is totally illusory.

    The general way that data is accessed in the storage system (e.g., file system) is via indexing. That way you don't need to read all the data into RAM just to find something. Indeed, this exact same 'trick' works in RAM as well. The basic idea is you have a sorted set of keys that are much smaller than the base data and you search the set of keys (index) to find the location of the bit you want. The index is much more likely to be kept in RAM (though not necessarily, really big databases have to have indexed into their indexes!) and by being sorted it isn't necessary to traverse the entire index in order to find the key. Then, with the key is a location in storage of the information you want to retrieve and there are ways to use that location to go directly to the location in the file without having to read the entire file into memory.

    All this seems quite silly when you are talking about a 'database' that is a few megabytes. However, if you go with the requirement of having your entire database in RAM, at some point your application will 'suddenly' drop in performance by 1,000x when RAM has been exhausted and the OS starts to write parts of your data back to disk (Google 'paging'). However, if you want to understand how to work at this level, these concepts are critical.

    Regarding databases, today the general method of accessing the data is to let a third-party set of libraries manage it for you (think MySQL, Postgresql, Sybase, Oracle, SQLServer, etc.). You use the language 'SQL' (which, I believe stands for 'structured query language', but it has been a very long time since I cared) to interact with the database engine. While I think it is a really good idea to build your own database to understand the guts and why certain things behave certain ways, in any sort of production environment you should use whatever commonly available product suits your needs (by studying database theory (get ready for 'tuples' and 'ACID'!) you become better able to evaluate the different database offerings).

    Just about every application of note has some sort of data store element. Sometimes it is 'just' an ini file, sometimes it is a terabyte database accessed over a network. Knowing how things work at this level will almost certainly make you a more valuable programmer.
    You must understand that this simple program is for the sole purpose of learning file I/O. By searching I meant searching a text file for information through the program. For example I believe this would be possible using by exhaustively using fscanf and comparing the strings in the file to the string inputted by the user. I hope this clarifies what I'm trying to ask. Please remember that this simple database program is for an introductory course for c language.
  6. #4
  7. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2012
    Posts
    186
    Rep Power
    82
    All ideas are welcome!
    How about using a sorted link list to hold your data? For example, when you first start your app, you will read your records from the database and load them into the sorted link list. Sorting of the records could be based on last name. Thus, you would update your menu to allow for searching, editing and deleting records and since the linked list is sorted, it will be faster to find specific records. Finally, the linked listed records would be written back to the database when the user terminates the app.

    Here is a linked list tutorial
  8. #5
  9. Banned ;)
    Devshed Supreme Being (6500+ posts)

    Join Date
    Nov 2001
    Location
    Woodland Hills, Los Angeles County, California, USA
    Posts
    9,607
    Rep Power
    4247
    Originally Posted by JoVillanueva
    I was wondering if any of you have ideas for editing strings in the text file, or searching for certain strings in a text file within the program?
    It is much easier to do this if you read/write fixed length records to the file. Instead of doing something like this:
    Code:
                fprintf(pDatabaseFile, "%s %s %s ", new.firstname, new.lastname, new.phone);  
                fprintf(pDatabaseFile, "%s %f\n", new.email, new.hourly_pay);
    You could do something like this:
    Code:
          if (fwrite(&new, sizeof(new), 1, pDatabaseFile) != sizeof(new) {
              /* Do some error handling here to say you couldn't write to the file */
          }
    and when reading the data from the file, instead of doing this:
    Code:
                fscanf(pDatabaseFile, "%s %s %s %s %f\n", viewInfo.firstname, viewInfo.lastname, viewInfo.phone, viewInfo.email, &viewInfo.hourly_pay);
    you could do this:
    Code:
            if (fread(&viewInfo, sizeof(viewInfo), 1, pDatabaseFile) != sizeof(viewInfo) {
                 /* Do some error handling here */
            }
            printf("%-10s %-13s %-13s %8.2f  %s \n", viewInfo.firstname, viewInfo.lastname, viewInfo.phone, viewInfo.hourly_pay, viewInfo.email);
    The disadvantage of this approach is that you waste some space if your struct elements are not filled out. The advantage is that your records are now fixed length, so you can quickly fseek() to any record you wish (say the 5th record in the file), without reading the preceding records first. You can also edit the records in place without rewriting the whole file, since your records are fixed length.

    Forgot to mention, if you plan on using fread() and fwrite(), it is a good idea to open your file in binary mode:
    Code:
        pDatabaseFile = fopen("Database.txt", "rb"); // file pointer uses fopen function to open file in read only mode
    ...
    ...
        pDatabaseFile = fopen("Database.txt", "ab");
    etc.
    Note that the open mode is "rb" and "ab" instead of "r" and "a". On a *NIX system, it makes no difference whether you enable binary mode or not, but on a Windows system it makes a difference.
    Up the Irons
    What Would Jimi Do? Smash amps. Burn guitar. Take the groupies home.
    "Death Before Dishonour, my Friends!!" - Bruce D ickinson, Iron Maiden Aug 20, 2005 @ OzzFest
    Down with Sharon Osbourne

    "I wouldn't hire a butcher to fix my car. I also wouldn't hire a marketing firm to build my website." - Nilpo
  10. #6
  11. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Dec 2012
    Posts
    5
    Rep Power
    0
    Originally Posted by BobS0327
    How about using a sorted link list to hold your data? For example, when you first start your app, you will read your records from the database and load them into the sorted link list. Sorting of the records could be based on last name. Thus, you would update your menu to allow for searching, editing and deleting records and since the linked list is sorted, it will be faster to find specific records. Finally, the linked listed records would be written back to the database when the user terminates the app.
    That sounds like a good idea. I'll look into that. Thanks!
  12. #7
  13. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Dec 2012
    Posts
    5
    Rep Power
    0
    Originally Posted by Scorpions4ever
    It is much easier to do this if you read/write fixed length records to the file. Instead of doing something like this:
    Code:
                fprintf(pDatabaseFile, "%s %s %s ", new.firstname, new.lastname, new.phone);  
                fprintf(pDatabaseFile, "%s %f\n", new.email, new.hourly_pay);
    You could do something like this:
    Code:
          if (fwrite(&new, sizeof(new), 1, pDatabaseFile) != sizeof(new) {
              /* Do some error handling here to say you couldn't write to the file */
          }
    and when reading the data from the file, instead of doing this:
    Code:
                fscanf(pDatabaseFile, "%s %s %s %s %f\n", viewInfo.firstname, viewInfo.lastname, viewInfo.phone, viewInfo.email, &viewInfo.hourly_pay);
    you could do this:
    Code:
            if (fread(&viewInfo, sizeof(viewInfo), 1, pDatabaseFile) != sizeof(viewInfo) {
                 /* Do some error handling here */
            }
            printf("%-10s %-13s %-13s %8.2f  %s \n", viewInfo.firstname, viewInfo.lastname, viewInfo.phone, viewInfo.hourly_pay, viewInfo.email);
    The disadvantage of this approach is that you waste some space if your struct elements are not filled out. The advantage is that your records are now fixed length, so you can quickly fseek() to any record you wish (say the 5th record in the file), without reading the preceding records first. You can also edit the records in place without rewriting the whole file, since your records are fixed length.

    Forgot to mention, if you plan on using fread() and fwrite(), it is a good idea to open your file in binary mode:
    Code:
        pDatabaseFile = fopen("Database.txt", "rb"); // file pointer uses fopen function to open file in read only mode
    ...
    ...
        pDatabaseFile = fopen("Database.txt", "ab");
    etc.
    Note that the open mode is "rb" and "ab" instead of "r" and "a". On a *NIX system, it makes no difference whether you enable binary mode or not, but on a Windows system it makes a difference.
    Thank you, I'll try using those statements and see how that goes. My friend suggested I used fgets also. Is this the same thing?
  14. #8
  15. Banned ;)
    Devshed Supreme Being (6500+ posts)

    Join Date
    Nov 2001
    Location
    Woodland Hills, Los Angeles County, California, USA
    Posts
    9,607
    Rep Power
    4247
    fgets() is not the same as fread(). fgets() reads up to N bytes or \n whichever comes first. fread() tries to read N bytes (completely ignores \n).
    Up the Irons
    What Would Jimi Do? Smash amps. Burn guitar. Take the groupies home.
    "Death Before Dishonour, my Friends!!" - Bruce D ickinson, Iron Maiden Aug 20, 2005 @ OzzFest
    Down with Sharon Osbourne

    "I wouldn't hire a butcher to fix my car. I also wouldn't hire a marketing firm to build my website." - Nilpo
  16. #9
  17. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Dec 2012
    Posts
    5
    Rep Power
    0
    Thanks for the help!

IMN logo majestic logo threadwatch logo seochat tools logo