I am trying to read lines of a file (cityName, hiTemp, loTemp) into a struct array. I was able to use >> to read the first several lines until I hit a city with a space in it's name.
I then tried using getline() to read the lines, but then my while loop stopped working.
I have no clue why this would happen.
int LoadData()
{
int count = 0;
string path;
cout << "Specify the input file path: ";
ifstream inFile;
cin >> path;
inFile.open(path.c_str());
if (!inFile.is_open())
{
cout << "Error - could not open file: " << path;
return (-1);
}
else
{
while (!inFile.eof())
{
cities[count].city = "";
getline(inFile, cities[count].city);
if (cities[count].city.length() == 0)
{
break;
}
char comma;
inFile >> (cities[count].high) >> comma >> cities[count].low;
cout << cities[count].city << " " << cities[count].high << " " << cities[count].low << endl;
count++;
}
inFile.close();
inFile.clear(std::ios_base::goodbit);
return count;
}
}
while (!inFile.eof())
For getting every line in the file, you should use:
while(getline(inFile, cities[count].city)) {
// ...
This works and is recommended over using the .eof() method.
You can also use this in your if-statement:
if (!getline(inFile, str))
break;
As an aside, you can read this site:
Why is “while ( !feof (file) )” always wrong? - StackOverflow post
It gives insight into why using the .eof() is not the preferred method to use in a while loop to check whether the end-of-file has been reached.
Use getline as loop condition. You can also replace the second read with a getline too and use a stringstream to parse it.
#include <sstream>
// ...
while(getline(inFile, cities[count].city)) {
if (cities[count].city.empty()) break;
// read next line with high and low values
string str;
if (!getline(inFile, str)) break; // error in file format
stringstream ss(str);
char comma;
ss >> cities[count].high >> comma >> cities[count].low; // parse it
}
Related
Basically I have a function, that writes into a .txt file.
The user has to input, what will be written in the file.
The problem is, every word has a new line, even tho it's written in the same line, while doing the input.
But I want it to be the way the user inputs it.
void Log_Write::WriteInLog(std::string LogFileName)
{
system("cls");
std::string input;
std::ofstream out;
out.open(LogFileName, std::fstream::app);
out << "\n\nNEW LOG ENTRY: " << getCurrentTime()<<"\n"; //
while (true)
{
system("cls");
std::cout << "Writing in Log\n\nType 'x' to leave editor!\n\nInsert new entry: ";
std::cin >> input;
if (input == "x")
break;
out << input << "\n"; // How do I change this so it doesn't create a new line for each word
}
out.close();
}
Sample Input:
1st Input:Test Input
2st Input:Next input
Sample Output in file.txt:
Test
Input
Next
Input
(Without the spaces in between!)
std::cin >> input; just reads to the first whitespace while std::getline(std::cin, input); would read the whole line.
One way of fixing it:
while(
system("cls"),
std::cout << "Writing in Log\n\nType 'x' to leave editor!\n\nInsert new entry: ",
std::getline(std::cin, input)
) {
if (input == "x")
break;
out << input << '\n';
}
I put the std::getline call last in the while condition to make the loop exit if std::getline fails.
Now, the above looks pretty nasty so I suggest putting clearing the screen and prompting the user in a separate function instead.
Example:
#include <iostream>
#include <string>
#include <string_view>
std::istream& prompt(std::string_view prompt_text, std::string& line,
std::istream& in = std::cin,
std::ostream& out = std::cout) {
std::system("cls");
out << prompt_text;
std::getline(in, line);
return in;
}
void Log_Write::WriteInLog(std::string LogFileName) {
// ...
auto prompt_text = "Writing in Log\n\n"
"Type 'x' to leave editor!\n\n"
"Insert new entry: ";
while (prompt(prompt_text, input)) {
if (input == "x") break;
out << input << '\n';
}
}
I want to make a factory class which creates and loads objects in from a file;
however when I try to read in a int from the file it appears to return a incorrect number.
std::ifstream input;
input.open("input.txt");
if (!input.is_open()){
exit(-1);
}
int number;
input >> number;
cout << number;
input.close();
When I enter a number in the input.txt file it shows: -858993460.
Changing the number doesn’t make a difference and when I use cin instead of ifstream it works like it should. I'm probably just missing something really stupid, but I can't figure it out.
Edit: Using getLine() works like it should. I guess there is a problem using >>.
Here is another solution to open a file a read it line by line:
string line;
ifstream myfile("input.txt");
if (myfile.is_open())
{
while ( getline (myfile,line) )
{
cout << line << '\n'; // Use this to verify that the number is outputed
// Here you can transform your line into an int:
// number = std::stoi(line);
}
// myfile.close(); Use this if you want to handle the errors
}
else cout << "Unable to open file";
If you don't want to read line by line, just remove the while
...
getline(myfile,line);
number = std::stoi(line);
...
Read multiple numbers in one line
Image that your input file is like this:
1, 2.3, 123, 11
1, 2
0.9, 90
Then, you can use this piece of code to read all the numbers:
string line;
ifstream myfile("input.txt");
string delimiter = ", ";
if (myfile.is_open())
{
while ( getline (myfile,line) )
{
cout << "Reading a new line: " << endl;
size_t pos = 0;
string token;
while ((pos = line.find(delimiter)) != string::npos) {
token = line.substr(0, pos);
cout << token << endl; // Instead of cout, you can transform it into an int
line.erase(0, pos + delimiter.length());
}
}
}
else cout << "Unable to open file";
The output will be:
Reading a new line:
1
2.3
123
11
Reading a new line:
1
2
Reading a new line:
0.9
90
New solution that may work =)
I didn't test this, but it works apparently:
std::ifstream input;
double val1, val2, val3;
input.open ("input.txt", std::ifstream::in);
if (input >> val1 >> val2 >> val3) {
cout << val1 << ", " << val2 << ", " << val3 << endl;
}
else
{
std::cerr << "Failed to read values from the file!\n";
throw std::runtime_error("Invalid input file");
}
To check the IO, see http://kayari.org/cxx/yunocheckio.html
I have a code like this, concerning stringstream. I found a strange behavior:
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;
int main()
{
int p, q;
fstream file;
string str;
stringstream sstr;
file.open("file.txt", ios::in);
if(file.is_open()) {
while(getline(file, str)) {
sstr << str;
sstr >> p >> q;
cout << p << ' ' << q << endl;
sstr.str("");
}
}
file.close();
return 0;
}
Suppose I have file.txt as
4 5
0 2
with return after 5 in the first line and 2 in the second line. The program gives me:
4 5
4 5
which means p and q are not correctly assigned. But I checked that each time sstr.str() with get the correct string of the line.
Why stringstream has a behaviour like this?
The stream is in a non-good state after reading the second integer, so you have to reset its error state before resuming.
Your real mistake was to not check the return value of the input operations, or you would have caught this immediately!
The simpler solution may be to not try to reuse the same stream, but instead make it anew each round:
for (std::string line; std::getline(file, line); )
{
std::istringstream iss(line);
if (!(iss >> p >> q >> std::ws) || !iss.eof())
{
// parse error!
continue;
}
std::cout << "Input: [" << p << ", " << q << "]\n";
}
When you read p, then q, you reach the end of your stream and the flag eofbit is set and you can't do anything anymore.
Just clear() it and your code will work as you expect.
But you may want to use directly file instead, and file.close(); will have a better place within your if:
fstream file;
file.open("file.txt", ios::in);
if(file.is_open()) {
int p, q;
while(file >> p >> q) {
cout << p << ' ' << q << endl;
}
file.close();
}
Your code has some redundant lines: fstream could be opened during the definition and no explicit file close() is needed, as it is automatically destroyed at the end of main().
Additionally, in your file reading loop, the line: sstr << str should be replaced with stringstream sstr(line); if you want to initialize a new stringstream for each line, which will make the line: sstr.str(""); redundant as well.
Applying the above corrections, here is your code:
int main() {
int p, q;
fstream file("file.txt", ios::in);
// check status
if (!file) cerr << "Can't open input file!\n";
string line;
// read all the lines in the file
while(getline(file, line)) {
// initialize the stringstream with line
stringstream sstr(line);
// extract line contents (see Note)
while (sstr >> p >> q) {
// print extracted integers to standard output
cout <<"p: " << p <<" q: "<< q << endl;
}
}
return 0;
}
Note: The line while (sstr >> p >> q) assumes that a line contains only integers, separated by white space.
#include <fstream>
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char filename[20] = "filename";
char userInput;
ofstream myFile;
cout << "Enter filename: ";
cin.getline(filename, sizeof(filename));
myFile.open(filename);
if(myFile.fail())
{
cout << "Error opening file: "
<< filename << "\n";
return 1;
}
cout << "Add text to the file: ";
cin.get(userInput);
while(cin.good() && userInput)
{
myFile.put(userInput);
cin.get(userInput);
}
myFile.close();
return 0;
}
Im having trouble terminating the input without force quiting it(It still writes to the file).
This is what I am supposed to do
Receives a line of input from the user, then outputs that
line to the given file. This will continue until the line input
by the user is “-1” which indicates, the end of input.
however I cannot work out the -1 part. Any help would be greatly appreciated everything else seems to work.
You're making things a bit more complicated than they need to be. Why C strings instead of std::string, for example? Using the right (standard-provided) classes generally leads to shorter, simpler and easier-to-understand code. Try something like this for starters:
int main()
{
std::string filename;
std::cout << "Enter filename" << std::endl;
std::cin >> filename;
std::ofstream file{filename};
std::string line;
while (std::cin >> line) {
if (line == "-1") {
break;
}
file << line;
}
}
First of all, the assignment asks to read a line from the user, character-wise input by get() shouldn't be the function to use. Use the member function getline() as you did to recieve the file name and use a comparison function to check against -1:
for (char line[20]; std::cin.getline(line, sizeof line) && std::cin.gcount(); )
{
if (strncmp(line, "-1", std::cin.gcount()) == 0)
break;
myFile.write(line, std::cin.gcount());
}
Those are the parts of the code I have:
ifstream inFile;
inFile.open("Product1.wrl");
...
if (!inFile.is_open()){
cout << "Could not open file to read" << endl;
return 0;
}
else
while(!inFile.eof()){
getline(inFile, line);
cout << line << endl; //this statement only to chech the info stored in "line" string
if (line.find("PointSet"))
inFile >> Point1;
}
The output shows me the same string over and over again. So this means that the cursor inside the file does not proceed and getline reads the same line.
What might be the problem of this odd behavior?
If this is relevant:
The file does open as a .txt file and contains the exact information I need.
Okay I figured the problem:
Even after first eteration the return value of line.find("PointSet")is: 429467295... while my line string contains only one letter "S". Why?
Change
while(!inFile.eof()){
getline(inFile, line);
to
while( getline(inFile, line) ) {
I don't know why people get bitten by eof() quite so often, but they do.
Mixing getline with >> is problematic, because the >> will leave a '\n' in the stream, so the next getline will come back empty. Change that to use getline as well.
if (line.find("PointSet")) isn't what you want either. find returns the position in the string, or std::string::npos if it wasn't found.
Also, you can change
ifstream inFile;
inFile.open("Product1.wrl");
to
ifstream inFile ("Product1.wrl");
Here's a version showing the reads:
class Point
{
public:
int i, j;
};
template <typename CharT>
std::basic_istream<CharT>& operator>>
(std::basic_istream<CharT>& is, Point& p)
{
is >> p.i >> p.j;
return is;
}
int main()
{
Point point1;
std::string line;
while(std::getline(std::cin, line))
{
std::cout << line << '\n'; //this statement only to chech the info stored in "line" string
if (line.find("PointSet") != std::string::npos)
{
std::string pointString;
if (std::getline(std::cin, pointString))
{
std::istringstream iss(pointString);
iss >> point1;
std::cout << "Got point " << point1.i << ", " << point1.j << '\n';
}
else
{
std::cout << "Uhoh, forget to provide a line with a PointSet!\n";
}
}
}
}