Thread: Reading from file into structs..

  1. #1
    dankas
    Guest

    Question Reading from file into structs..

    Dear All,

    After spending a great deal of time searching previous posts, I am still stuck with the following. Essentially I am trying to open and read from a file, storing the file data into a struct. Please see below:

    here is my struct declared in my header file....

    Code:
    typedef struct {
       int carsSold[MAX_BRANDS];  
       float carSaleValue;     
    }CarSales;
    now i need to open an existing file and read the data into the above struct. the file data is in the following format ...

    20,20100.20
    15,15100.50

    .. and here is my code so far (not very far i know!)....

    Code:
    FILE *fptr = NULL;
    CarSales s;
    int j;
    
    /* open car sales file for reading */
    fptr = fopen("Sales.txt", "r");
    
    /* check to see if car sales file opened succesfully */
    if(fptr == NULL){
       printf("Failed to open car sales file for reading.\n");
    }
    what would the best method be to read the file data and store it in the struct? any ideas would be appreciated!

    cheers,

    dankas

  2. #2
    Im back! shaik786's Avatar
    Join Date
    Jun 2002
    Location
    Bangalore, India
    Posts
    345
    First of all, your struct need to be like:
    Code:
    typedef struct {
       int carsSold;
       float carSaleValue;
    }CarSales[MAX_BRANDS];
    Secondly, if the data in the file appears in a constant fashion as mentioned above by you, you can use:
    Code:
    fscanf(fptr, "%d,%f", &CarSales[i].carsSold, &CarSales[i].carSaleValue);
    /*   where 'i' is declared and initialzed earlier   */

  3. #3
    dankas
    Guest
    thanks shaik786.

    i shall attempt to implement the suggested code. i do however have a more complex struct to also load that includes a nested struct - please see below:

    Code:
    typedef struct date {
       int day;  
       int month;  
       int year;  
    }Date;
    
    typedef struct {
       Date dt;              
       int numBuses[MAX_CLASS];  
       int valueOfBus;     
    }BusStruct[];
    the file for this is in the following format:

    22/10/01,20,21500
    23/10/01,20,22780

    Any suggestions? Can I implement similar code as suggested for the first struct? How do I deal with the nested struct?

    Any help much appreciated!

    Cheers,

    dankas

  4. #4
    Im back! shaik786's Avatar
    Join Date
    Jun 2002
    Location
    Bangalore, India
    Posts
    345
    Yes, the code will be very to similar to what was said in the earlier post, only:
    Code:
    fscanf(fptr, "%d/%d/%d,%d,%f", &BusTruct[i].dt.day, &BusTruct[i].dt.month, &BusTruct[i].dt.year, &CarSales[i].carsSold, &CarSales[i].carSaleValue);
    And AGAIN, in your structure definition of 'BusStruct' you don't need the MAX_CLASS inside the structure. You are instead going to create that many number of structures. So, your definition would be:

    Code:
    typedef struct {
       Date dt;
       int numBuses;
       int valueOfBus;
    }BusStruct[MAX_CLASS];

  5. #5
    dankas
    Guest
    thanks once again..... i have implemented the code but i am getting the error:

    "subscripted value is neither array nor pointer"

    any ideas?

    cheers,

    dankas

  6. #6
    dankas
    Guest
    thanks for the comments.... here is my latest code (note that the structs are slightly different but you will get the idea)...

    structs....

    Code:
    /* declare structure for date */
    typedef struct date {
       int dd;  /* day */
       int mm;  /* month */
       int yy;  /* year */
    }Date;
    
    /* declare structure for sales log */
    typedef struct {
       Date dt;               
       int canSold[MAX_BRANDS]; 
       double valueOfSale; 
    }LogType;
    file to read has format of:

    22/10/01,20,2.25
    23/10/01,20,2.50

    latest code to try and read file data into struct is:

    in main i call function to load struct:

    Code:
    /* load sales data */
       for (i = 0; i < MAX_LOG; i++){
          salesInfo[i] = load_sales(dt, canSold, valueOfSale, i, f2);
       }
    here is the load function:

    Code:
    LogType load_sales(Date dt, int canSold, double valueOfSale, int i, char f2[])
    {
       LogType l;
    
       char filename2[MAX_PASS + 1];
       FILE *fptr2 = NULL;
    
       strcpy(filename2, f2);
       printf("%s\n", filename2);
    
    /* open sales file for reading */
       fptr2 = fopen(filename2, "r");
       if(fptr2 == NULL){
          printf("Failed to open file for reading.\n");
       }
    
    /* load data into struct */
       fscanf(fptr2, "%d/%d/%d,%d,%f", &l[i].dt.dd, &l[i].dt.mm, &l[i].dt.yy, &l[i].canSold, &l[i].valueOfSale);
       
    }
    NB: that f2 is simply the filename that is passed to the load function.

    I am getting the error at line leading with fscanf as mentioned just above (below /* load data into struct */).

    I appreciate all the help!

    dankas

  7. #7
    Banned master5001's Avatar
    Join Date
    Aug 2001
    Location
    Visalia, CA, USA
    Posts
    3,685
    Generally speaking, unless you absolutely need to read your database manually (like this:

    Anderson, John H 12/29/76
    Andrews, Jane M 1/15/80
    ....

    ) you shouldn't write them this way. Most programs tend to write out structures into a binary.

    So that a struct that looks like this:

    Code:
    struct info {
        char name[16];
        char month, day, year;
    };
    Can be written to a file and look like this:

    Code:
    Ben Franklin    *
    
    //deverived from the struct
    struct info ben;
    strcpy(ben, "Ben Franklin");
    ben.month = ben.day = 1;
    ben.year = 42;
    //these are just random number not his birthday
    You can simply read this back into a struct and would need to do no parsing.

  8. #8
    Just Lurking Dave_Sinkula's Avatar
    Join Date
    Oct 2002
    Posts
    5,005
    Originally posted by master5001
    Generally speaking, unless you absolutely need to read your database manually you shouldn't write them this way. Most programs tend to write out structures into a binary.
    ...
    You can simply read this back into a struct and would need to do no parsing.
    This is the opposite of advice I've seen previously. I am assuming you are advocating something like the following.
    Code:
    #include<stdio.h>
    int main(void)
    {
       struct info
       {
          char name[16];
          char month, day, year;
       } data = { "Dave_Sinkula", 3, 8, 70};
       FILE *file = fopen("test.txt", "wb");
       if(file)
       {
          if(fwrite(&data, sizeof(data), 1, file) != 1)
          {
             fprintf(stderr, "%s\a\n", "fwrite failed");
          }
          fclose(file);
       }
       return(0);
    }
    If so, note that this is not necessarily portable from platform to platform, compiler to compiler, or even with the same compiler when compiled with different options. And being human readable does have its advantages.

  9. #9
    dankas
    Guest

    Thumbs up

    thanks everyone for you assistance. i shall play around with the suggested approaches and post my solution.

    once again cheers!

    dankas

  10. #10
    dankas
    Guest
    hi all.

    well i have implemented the original suggestion and have managed to load the struct with the first line of text within the file.

    i still do have the problem of trying to load additional lines of text from the file...... the code works fine for one line, but any more lines of file data and i get an error "Bus Error".

    here is a snippet of the code that calls the load struct function:

    Code:
    /* load sales transaction log data into struct */
       for (i = 0; i < MAX_LOG; i++){
          salesInfo[i] = load_sales(dt, canSold, valueOfSale, i, f2);
       }
    and here is the load function:

    Code:
    /* function to load sales info. into log struct */
    LogType load_sales(Date dt, int canSold, float valueOfSale, int i, char f2[])
    {
    /* intialise variables */
       LogType l;
       FILE *fptr2 = NULL;
    
    /* open sales file for reading */
       fptr2 = fopen(f2, "r");
       if(fptr2 == NULL){
          printf("ERROR: Failed to open sales file for reading.\n");
       }
    
    /* load sales data into struct */
       fscanf(fptr2, "%d,%d,%d,%d,%f", &l.dt.dd, &l.dt.mm, &l.dt.yy, &l.canSold[0], &l.valueOfSale);
    
    /* close sales file */
       fclose(fptr2);
    
       return l;
    }
    any ideas on how to load multiple lines from the text file into the struct array?

    cheers..... dankas

  11. #11
    Im back! shaik786's Avatar
    Join Date
    Jun 2002
    Location
    Bangalore, India
    Posts
    345
    Read Salem's earlier post, you have the solution there.

  12. #12
    dankas
    Guest

    Question

    thanks shaik786.

    i am very new to C hence please excuse my ignorance, but how exactly would i go about doing that? do i need to pass a pointer to the file that holds the data and read from the sales function into the buffer, then in the main read the buffer into the struct?

    if you can point me (excuse the pun) in the right direction it would be appreciated.

    cheers,

    dankas

  13. #13
    Im back! shaik786's Avatar
    Join Date
    Jun 2002
    Location
    Bangalore, India
    Posts
    345
    Look closely into your load_sales() function. You call this function for MAX_LOG number of times. Inside this function, you open the same file again and again and close it. Every time you open a file, the file pointer points to the first byte in the file. So, no matter how many times you call this function, the data returned will always be the first line present in the file.
    To solve this problem, what you can do is, fopen() the file just before the for loop and inside the load_sales() function, remove the code for fopen()/fclose(). Rest all looks good.
    I hope this helps.

  14. #14
    Banned master5001's Avatar
    Join Date
    Aug 2001
    Location
    Visalia, CA, USA
    Posts
    3,685
    Dave_Sinkula, your code about sums up what I said. Here is the reason why most people do not agree with me. If you take a piece of data from one machine to another (usually the case with databases) the way bytes are read may be different. So a short may be stored like this:

    high byte, low byte
    or
    low byte, high byte

    Therefore it isn't as portable as far as reading data goes. However, unless you are making a program that needs to have its output read on multiple machines you should use binary. Once gain, unless you have to use a plain text format then don't. Many databases are private and hold information such as employee information. This could do just fine as a binary database. Other databases may store information like peoples driving records that may be read by thousands of computers across the world--this needs to be more portable.

  15. #15
    Just Lurking Dave_Sinkula's Avatar
    Join Date
    Oct 2002
    Posts
    5,005
    Originally posted by master5001
    Dave_Sinkula, your code about sums up what I said. Here is the reason why most people do not agree with me. If you take a piece of data from one machine to another (usually the case with databases) the way bytes are read may be different.
    Endianness and ints, yes, but how is this a problem for strings?

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. opening empty file causes access violation
    By trevordunstan in forum C Programming
    Replies: 10
    Last Post: 10-21-2008, 11:19 PM
  2. sequential file program
    By needhelpbad in forum C Programming
    Replies: 80
    Last Post: 06-08-2008, 01:04 PM
  3. Game Pointer Trouble?
    By Drahcir in forum C Programming
    Replies: 8
    Last Post: 02-04-2006, 02:53 AM
  4. Possible circular definition with singleton objects
    By techrolla in forum C++ Programming
    Replies: 3
    Last Post: 12-26-2004, 10:46 AM
  5. System
    By drdroid in forum C++ Programming
    Replies: 3
    Last Post: 06-28-2002, 10:12 PM