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

A

AMT2K5

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.
 
T

titancipher

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.
 
K

Karl Heinz Buchegger

AMT2K5 said:
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.
 
J

jason

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
 
K

Karl Heinz Buchegger

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

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.
 
A

AMT2K5

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

I am trying to interpret your code.
 
P

Puppet_Sock

AMT2K5 said:
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
 
J

jason

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.
 
H

Howard

jason said:
{
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
 
A

AMT2K5

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

red floyd

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.
 
A

AMT2K5

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 said:
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.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Staff online

Members online

Forum statistics

Threads
473,755
Messages
2,569,534
Members
45,007
Latest member
obedient dusk

Latest Threads

Top