?
Solved

How to read multi-word strings from a file

Posted on 2003-03-28
13
Medium Priority
?
317 Views
Last Modified: 2008-01-16

Plz examin the following code.

struct employee
{
     int code;
     char name[100];
     float salary;
};

void main()
{
     employee e1;
     ofstream f1("Employee.txt");
     for(int i=1;i<=10;i++)
     {
          cout<<"Enter Code, Name and Salary : ";
          cin>>e1.code>>e1.name>>e1.sal;
          f1<<e1.code"\t"<<e1.name<<"\t"<<e1.salary;
     }
}
     
   This will write 10 employee records on to a file "Employee.txt".
Assume that the employee name is a multi-word string. Then,
how to read it back from that file ?

void main()
{
     struct employee e1;
     ifstream f1("Employee.txt");
     while(!f1.eof())
     {
          f1>>e1.code>>e1.name>>e1.salary;
          cout<<"\n\n\t"<<e1.code<<"\t"<<e1.name<<"\t"<<e1.salary;
     }
}

   This won't work. The overloaded extraction operator is not
capable of reading multi-word strings from a file.

   Plz suggest a solution for this problem.
0
Comment
Question by:balakiran_bs
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 3
  • 3
  • +2
13 Comments
 
LVL 8

Expert Comment

by:Exceter
ID: 8225560
You need to use getline to accomplish this. For example,

#include <iostream>
#include <fstream>

using namespace std;

int main()
{
    char name[100];
    ifstream in( "test.txt", ios::in );
    in.getline( name, 100, '\n' );
    cout << name << endl;
    return 0;
}

-- Test.txt --

My name is Exceter

-- output --

My name is Exceter

Exceter
0
 
LVL 8

Accepted Solution

by:
Exceter earned 100 total points
ID: 8225594
Oops, I forgot to leave space on the end of name to account for the null byte. This would not bother unless getline actually read in 100 charcters from disk. In which case it would attempt to assign the bull byte to position 100 which does not exist as name's highest index is 99. So the following,

>> in.getline( name, 100, '\n' );

should be,

in.getline( name, 99, '\n' );

Exceter
0
 
LVL 12

Assisted Solution

by:Salte
Salte earned 100 total points
ID: 8225618
I will suggest you use some form of field separator which isn't space between each field. The reason why it shouldn't be space is that space is a legal character in the name (which is why it is multi word).

so, assuming you use ':' or ',' or whatever to separate the code, name and salary you can simple read it like this:

f1 >> e1.code;
f1.ignore(1024,':'); // read and ignore until ':'
f1.getline(e1.name,':'); // read name
f1.ignore(1,':'); // read and ignore the ':'
f1 >> e1.salary
f1.ignore(1024,'\n');

I would believe you also have to do something similar in the input from user, except you typically don't use a separator character in that case but rather have separate questions, if you want you can use a separator character in that case too, if so the code is similar to the above.

Also, I notice you have some 'nuisance' in your original code and my code above assume you have fixed that. You do not terminate the record with a newline character, so the whole file becomes one huge line with code, name, salary, code, name, salary etc... such a file will be very difficult to read if you want to read it in an editor and so I suggest you rather insert a end of line after each salary so that each employee's record comes on a line of its own.

So add a << endl after the salary when you make the file.

Alf
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 8

Expert Comment

by:Exceter
ID: 8225628
The problem you are experiencing is simply that all in streams break when they encounter a space character because they are derived from the same base class. You will notice the same phenomenon when you use cin. For example,

char name[100];
cin >> name;

Type multiple words. You will notice that only the first word is stored in name.

Exceter
0
 
LVL 12

Expert Comment

by:Salte
ID: 8225786
One thing,

my getline() is a bit fast, you need an argument specifying the size of the array also:

f1.getline(e.name,sizoef(e.name),':');

is correct usage.

f1.getline(...,...,':');

will not break at space but will break at ':' (or whatever character you choose for your field separator character).

Alf
0
 
LVL 40

Expert Comment

by:Kyle Abrahams
ID: 8229445
You could also use string.append(source, stuff to append); if you wanted to keep each thing separate.
0
 
LVL 30

Expert Comment

by:Mayank S
ID: 8236605
I would suggest that you write an entire object to the file and read an entire object from the file instead of reading/ writing strings and numbers at the same time.

Mayank.
0
 
LVL 8

Expert Comment

by:Exceter
ID: 8243245
>> I would suggest that you write an entire object to the file and read an entire object from the file instead of reading/ writing strings
>> and numbers at the same time.

How would you go about doing that? As I understand things, object serialization is not nearly as simple in C++ as it is in other languages, such as Java for example.

Exceter
0
 
LVL 30

Expert Comment

by:Mayank S
ID: 8243294
Why can't you use the read (), write () functions:

class Employee
{    
  int code ;
  char name[100] ;
  double salary ;
public:
  ..
  .. // memner functions

} ;
 
..
.. // in some member function
ofstream fout ;
four.write ( ( char * ) this, sizeof ( * this ) ) ;

..
..
ifstream fin ;
fin.read ( ( char * ) this, sizeof ( * this ) ) ;

Mayank.
0
 
LVL 12

Expert Comment

by:Salte
ID: 8244476
Mayank,

that gives a binary file (should be opened with ios::binary) and might be difficult if he wants to inspect the file using a regular editor.

The specification he originally gave is such that a file using some specific character (not space) to separate the fields should be perfect. I would use either ':' or ';' but virtually any character that doesn't occur in his data can be used.

getline() will then read the file correctly up to but not including the stop character. Using the separator character as stop character for getline() will then get him the current field.

Alf
0
 
LVL 30

Expert Comment

by:Mayank S
ID: 8244521
Actually, the questioner simply asked that how should he read the name if it contains multiple words. Personally, whenever I have to write a structure or an entire object into a file, I always prefer the read () and write () functions, simply because I find them very easy to use and yet very effective. I agree that we get a binary file, but as long as we're not editing the file directly but accessing it only through the program, it gives a very handy way to read data directly into your structure variable (or object).

As per his specifications, if a delimiting character has to be specified for every element in the record (and assuming that he also wants to use an editor to read the file, not just the program), I think it’ll be better to simply write every element in a new-line, e.g.,

Code
Name
Salary

Code
Name
Salary

And individual records can be identified after every 3 or 4 new-lines.

I wonder what he is doing.... he's already got enough comments here to solve his problem in many different ways!

Cheers,

Mayank.
0
 
LVL 9

Expert Comment

by:tinchos
ID: 9566463
No comment has been added lately, so it's time to clean up this TA.
I will leave a recommendation in the Cleanup topic area that this question is:

Split points between Exceter & Salte

Please leave any comments here within the next seven days.

PLEASE DO NOT ACCEPT THIS COMMENT AS AN ANSWER!

Tinchos
EE Cleanup Volunteer
0

Featured Post

Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Unlike C#, C++ doesn't have native support for sealing classes (so they cannot be sub-classed). At the cost of a virtual base class pointer it is possible to implement a pseudo sealing mechanism The trick is to virtually inherit from a base class…
This article will show you some of the more useful Standard Template Library (STL) algorithms through the use of working examples.  You will learn about how these algorithms fit into the STL architecture, how they work with STL containers, and why t…
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.

800 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