Reading Lines with Fgets(?) and a bit of C++ {Novice Programmer}

Discussion in 'C++' started by AMT2K5, Jul 6, 2005.

  1. AMT2K5

    AMT2K5 Guest

    Hello.
    I have a file (for a school assignment) with the following format and
    delimiter format. Each record in the file has the following format:
    123423454567987,29873,James,Ha­rry,St. Louis,416-555-5555;
    "accountNumber,balance,lastNam­e,city,phoneNumber;" Each record is
    guranteed to be no longer than 350 characters. "balance" is no longer
    than 20 characters, "accountNumber" is exactly 15 characters and the
    total number of characters in "lastName,firstName,city,phone­Number;"
    is
    no longer than 315 characters. Copy the fields in this record to the
    appropriate data member of the first empty Account in the array
    savings, using all the rules for copying (initializing).


    Contents of a3.dat


    123423454567987,29873,James,Ha­rry,St.
    Louis,416-555-5555;22342345456­7987,198745,Jones,Beth,Toronto­,416-555-5556;323423454567987,­2349,Ng,Wei,Montreal,416-555-5­557;423423454567987,9234617,Wo­o,Charles,Winnipeg,416-555-555­8;523423454567987,2534,DeJesus­,Pancho,Edmonton,416-555-5559;­623423454567987,543876,Smith,B­ob,Charlottetown,416-555-5544;­723423454567987,1234,Kasim,Vla­dislov,Halifax,416-555-5566;82­3423454567987,98765,Yamaha,Dav­id,Vancouver,416-555-5577;9234­23454567987,26486,Lee,Jim,Calg­ary,416-555-5588;1134234545679­87,83456,Baker,Susan,St.

    Louis-de-ha-ha,416-555-5599;13­3423454567987,29873,James,Harr­y,St.
    Louis,416-555-5555;


    Since each "record" is not a line and is shown as is (above) in the
    file, how might I go and read each "record", extract the information
    and send it to the correct data member of the first empty object in the
    array?

    So far I have my function like this

    void Bank::workFP(FILE* fp)
    {
    if(fp != NULL){

    }
    else printf("Unable to open file.\n");
    }


    Thanks in advance. Appreciate any help whatsoever.
     
    AMT2K5, Jul 6, 2005
    #1
    1. Advertising

  2. AMT2K5

    titancipher Guest

    It's not "nice" because the data file is intentionally jumbled. One
    way to do this is to read exactly 350 characters, and parse it
    according to the rules you've outlined for the data elements. Then,
    save-off the remainder. Loop again, and read another 350, prepend the
    remainder and continue. Keep in mind that you will not have nice NULL
    terminated strings, and also check that you read 350 characters.
     
    titancipher, Jul 6, 2005
    #2
    1. Advertising

  3. AMT2K5 wrote:
    >
    >
    > Since each "record" is not a line and is shown as is (above) in the
    > file, how might I go and read each "record"


    From your description: Each "record" ends with a ';' character.
    So read character by character until you encounter a ';'. Save those
    characters in a buffer (probably a std::string). Then you have all
    characters for one record and can proceed to break it into
    individual pieces.

    --
    Karl Heinz Buchegger
     
    Karl Heinz Buchegger, Jul 6, 2005
    #3
  4. AMT2K5

    jason Guest

    since you can't guarantee that each record occupies it's own line, then
    you will have to read the whole file into memory. if you can gaurantee
    that the file is not of huge size, then you can just read the while
    file into a char* buffer, or a std::string object:

    if (fp != NULL)
    {
    char *chunk = new char[256];
    std::string sBuffer;
    while (!feof(fp))
    {
    fread(chunk, sizeof(char), 256, fp); // you might even be able to
    read right into the string struct, but i'm not sure
    string = string + sBuffer;
    }
    delete[] chunk;
    chunk = null;
    DoParsingAndOtherStuff(string);
    }

    once you have the whole file in a buffer, it's easy to use string
    manipulation to parse it, first by ';' to get the records, then by ','
    to get the fields in each record.

    if you can't gaurantee that the file is reasonable in size, then it
    gets trickier. you have to analyze each chunk for records first, and
    then do an fseek to get to the last place in the file you left off:

    if (fp != NULL)
    {
    char *chunk = new char[256];
    int nextstartposition = 0;
    while (!feof(fp))
    {
    fseek(fp, nextstartposition, 0);
    fread(chunk, sizeof(char), 256, fp);
    nextstartposition = nextstartposition +
    DoParsingAndOtherStuff(chunk)
    }
    delete[] chunk;
    chunk = null;
    }

    in this case DoParsingAndOtherStuff does the same thing, but it has to
    return the position that the last ';' was found on, because everything
    after that was only a partial record. then the file can seek to that
    new starting location, and read another chunk. it's only a little
    trickier than reading the whole thing into memory, really.

    if you need help with what DoParsingAndOtherStuff would look like, let
    me know.

    hope this helps,

    jason
     
    jason, Jul 6, 2005
    #4
  5. AMT2K5

    AMT2K5 Guest

    How can I program my loop to read the next record after the first ';'?


    Karl Heinz Buchegger wrote:
    > AMT2K5 wrote:
    > >
    > >
    > > Since each "record" is not a line and is shown as is (above) in the
    > > file, how might I go and read each "record"

    >
    > From your description: Each "record" ends with a ';' character.
    > So read character by character until you encounter a ';'. Save those
    > characters in a buffer (probably a std::string). Then you have all
    > characters for one record and can proceed to break it into
    > individual pieces.
    >
    > --
    > Karl Heinz Buchegger
    >
     
    AMT2K5, Jul 6, 2005
    #5
  6. AMT2K5 wrote:
    >
    > How can I program my loop to read the next record after the first ';'?
    >
    > Karl Heinz Buchegger wrote:
    > > AMT2K5 wrote:
    > > >
    > > >
    > > > Since each "record" is not a line and is shown as is (above) in the
    > > > file, how might I go and read each "record"

    > >
    > > From your description: Each "record" ends with a ';' character.
    > > So read character by character until you encounter a ';'. Save those
    > > characters in a buffer (probably a std::string). Then you have all
    > > characters for one record and can proceed to break it into
    > > individual pieces.
    > >
    > > --
    > > Karl Heinz Buchegger
    > >


    As said: you can read character by character. eg.

    std::string buffer;
    char c;

    while( fin >> c ) {
    if( c == ';' ) {
    // buffer contains a record, process it
    Process( buffer );
    buffer = "";
    }
    else
    buffer += c;
    }

    Not very fast, but it does its job.

    --
    Karl Heinz Buchegger
     
    Karl Heinz Buchegger, Jul 6, 2005
    #6
  7. AMT2K5

    AMT2K5 Guest

    What is that string = string come from? What is string?

    I am trying to interpret your code.

    jason wrote:
    > since you can't guarantee that each record occupies it's own line, then
    > you will have to read the whole file into memory. if you can gaurantee
    > that the file is not of huge size, then you can just read the while
    > file into a char* buffer, or a std::string object:
    >
    > if (fp != NULL)
    > {
    > char *chunk = new char[256];
    > std::string sBuffer;
    > while (!feof(fp))
    > {
    > fread(chunk, sizeof(char), 256, fp); // you might even be able to
    > read right into the string struct, but i'm not sure
    > string = string + sBuffer;
    > }
    > delete[] chunk;
    > chunk = null;
    > DoParsingAndOtherStuff(string);
    > }
    >
    > once you have the whole file in a buffer, it's easy to use string
    > manipulation to parse it, first by ';' to get the records, then by ','
    > to get the fields in each record.
    >
    > if you can't gaurantee that the file is reasonable in size, then it
    > gets trickier. you have to analyze each chunk for records first, and
    > then do an fseek to get to the last place in the file you left off:
    >
    > if (fp != NULL)
    > {
    > char *chunk = new char[256];
    > int nextstartposition = 0;
    > while (!feof(fp))
    > {
    > fseek(fp, nextstartposition, 0);
    > fread(chunk, sizeof(char), 256, fp);
    > nextstartposition = nextstartposition +
    > DoParsingAndOtherStuff(chunk)
    > }
    > delete[] chunk;
    > chunk = null;
    > }
    >
    > in this case DoParsingAndOtherStuff does the same thing, but it has to
    > return the position that the last ';' was found on, because everything
    > after that was only a partial record. then the file can seek to that
    > new starting location, and read another chunk. it's only a little
    > trickier than reading the whole thing into memory, really.
    >
    > if you need help with what DoParsingAndOtherStuff would look like, let
    > me know.
    >
    > hope this helps,
    >
    > jason
     
    AMT2K5, Jul 6, 2005
    #7
  8. AMT2K5

    Puppet_Sock Guest

    AMT2K5 wrote:
    > What is that string = string come from? What is string?

    [snip]

    You will need to get and read one of the fine introductory
    textbooks on C++. The stuff you are talking about is fairly
    elementary. For example, Koenig and Moo, _Accelerated C++_
    is well thought of. Also, your instructor should have said
    what text you should be reading, and you should be reading it.
    Socks
     
    Puppet_Sock, Jul 6, 2005
    #8
  9. AMT2K5

    jason Guest

    it's from the std library. if you can't use such things in your
    assignment, then char arrays work well too, though then it will be much
    easier to just process each chunk that you pull out, so that you're not
    constantly resizing the char array for the full file buffer.

    either Karl or my samples should work. his processes character by
    character, mine in larger chunks. both should be fine for an assignment.
     
    jason, Jul 6, 2005
    #9
  10. AMT2K5

    Howard Guest

    "jason" <> wrote in message

    > {
    > char *chunk = new char[256];
    > std::string sBuffer;
    > while (!feof(fp))
    > {
    > fread(chunk, sizeof(char), 256, fp); // you might even be able to
    > read right into the string struct, but i'm not sure
    > string = string + sBuffer;
    > }
    > delete[] chunk;
    > chunk = null;
    > DoParsingAndOtherStuff(string);
    > }
    >


    Why would you allocate and delete a buffer like that? Why not just declare
    a local array? Just because fread takes a pointer does not mean you have to
    _declare_ a pointer. All that function wants is the address of the first
    element, which you can get with either just "chunk" or "&chunk[0]". (If you
    can avoid using new and delete, it's generally better to do so, both because
    it is faster and because it's less error-prone.)

    -Howard
     
    Howard, Jul 6, 2005
    #10
  11. AMT2K5

    AMT2K5 Guest

    I just want to keep this as simple as possible. For parsing and working
    with the fields is it suggessted that I use strtok?

    AMT2K5 wrote:
    > Hello.
    > I have a file (for a school assignment) with the following format and
    > delimiter format. Each record in the file has the following format:
    > 123423454567987,29873,James,Ha­rry,St. Louis,416-555-5555;
    > "accountNumber,balance,lastNam­e,city,phoneNumber;" Each record is
    > guranteed to be no longer than 350 characters. "balance" is no longer
    > than 20 characters, "accountNumber" is exactly 15 characters and the
    > total number of characters in "lastName,firstName,city,phone­Number;"
    > is
    > no longer than 315 characters. Copy the fields in this record to the
    > appropriate data member of the first empty Account in the array
    > savings, using all the rules for copying (initializing).
    >
    >
    > Contents of a3.dat
    >
    >
    > 123423454567987,29873,James,Ha­rry,St.
    > Louis,416-555-5555;22342345456­7987,198745,Jones,Beth,Toronto­,416-555-5556;323423454567987,­2349,Ng,Wei,Montreal,416-555-5­557;423423454567987,9234617,Wo­o,Charles,Winnipeg,416-555-555­8;523423454567987,2534,DeJesus­,Pancho,Edmonton,416-555-5559;­623423454567987,543876,Smith,B­ob,Charlottetown,416-555-5544;­723423454567987,1234,Kasim,Vla­dislov,Halifax,416-555-5566;82­3423454567987,98765,Yamaha,Dav­id,Vancouver,416-555-5577;9234­23454567987,26486,Lee,Jim,Calg­ary,416-555-5588;1134234545679­87,83456,Baker,Susan,St.
    >
    > Louis-de-ha-ha,416-555-5599;13­3423454567987,29873,James,Harr­y,St.
    > Louis,416-555-5555;
    >
    >
    > Since each "record" is not a line and is shown as is (above) in the
    > file, how might I go and read each "record", extract the information
    > and send it to the correct data member of the first empty object in the
    > array?
    >
    > So far I have my function like this
    >
    > void Bank::workFP(FILE* fp)
    > {
    > if(fp != NULL){
    >
    > }
    > else printf("Unable to open file.\n");
    > }
    >
    >
    > Thanks in advance. Appreciate any help whatsoever.
     
    AMT2K5, Jul 6, 2005
    #11
  12. AMT2K5

    red floyd Guest

    jason wrote:
    [redacted]

    > if (fp != NULL)
    > {
    > char *chunk = new char[256];
    > std::string sBuffer;
    > while (!feof(fp))
    > {
    > fread(chunk, sizeof(char), 256, fp); // you might even be able to
    > read right into the string struct, but i'm not sure
    > string = string + sBuffer;
    > }
    > delete[] chunk;
    > chunk = null;
    > DoParsingAndOtherStuff(string);
    > }


    in addition to Howard's comment on allocating "chunk", you also have the
    usage of feof incorrect. feof doesn't kick in until you try to read and
    actually have alreay hit EOF. It's not predictive like Pascal.

    while (fread(chunk, sizeof(char), 256, fp) > 0)
    {
    // ...
    }

    Also, sizeof(char) is redundant since by definition it's 1, but it's
    probably better to use it since you may in the future want to go to wchar_t.

    Perhaps

    while (fread(chunk,sizeof(chunk[0]), 256, fp) > 0)
    {
    // ...
    }

    which then becomes independent of the size of your character.
     
    red floyd, Jul 6, 2005
    #12
  13. AMT2K5

    AMT2K5 Guest

    Thanks for the help guys. I asked my prof for extra help today and he
    suggested that I use fscanf.

    Now I am using it but I am having trouble with my format string. I can
    display the first fields fine, but the (%315) field I can not. I get a
    single garbage character on my screen if I display it.

    char accountTemp[16];
    int balanceTemp = 0;
    char stringTemp[316];

    fscanf(fp, "%15[^,],%20d[^,],%315[^;]", accountTemp, &balanceTemp,
    stringTemp);

    red floyd wrote:
    > jason wrote:
    > [redacted]
    >
    > > if (fp != NULL)
    > > {
    > > char *chunk = new char[256];
    > > std::string sBuffer;
    > > while (!feof(fp))
    > > {
    > > fread(chunk, sizeof(char), 256, fp); // you might even be able to
    > > read right into the string struct, but i'm not sure
    > > string = string + sBuffer;
    > > }
    > > delete[] chunk;
    > > chunk = null;
    > > DoParsingAndOtherStuff(string);
    > > }

    >
    > in addition to Howard's comment on allocating "chunk", you also have the
    > usage of feof incorrect. feof doesn't kick in until you try to read and
    > actually have alreay hit EOF. It's not predictive like Pascal.
    >
    > while (fread(chunk, sizeof(char), 256, fp) > 0)
    > {
    > // ...
    > }
    >
    > Also, sizeof(char) is redundant since by definition it's 1, but it's
    > probably better to use it since you may in the future want to go to wchar_t.
    >
    > Perhaps
    >
    > while (fread(chunk,sizeof(chunk[0]), 256, fp) > 0)
    > {
    > // ...
    > }
    >
    > which then becomes independent of the size of your character.
     
    AMT2K5, Jul 6, 2005
    #13
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Roedy Green

    Little job for novice programmer

    Roedy Green, Sep 9, 2003, in forum: Java
    Replies:
    0
    Views:
    358
    Roedy Green
    Sep 9, 2003
  2. AMT2K5
    Replies:
    6
    Views:
    746
    Larry I Smith
    Jun 9, 2005
  3. AMT2K5
    Replies:
    6
    Views:
    869
    AMT2K5
    Jul 6, 2005
  4. Justme
    Replies:
    9
    Views:
    619
    clayne
    Oct 1, 2006
  5. Replies:
    43
    Views:
    1,946
    U S Contractors Offering Service A Non-profit
    Nov 30, 2006
Loading...

Share This Page