ifstream does not work in loop - c++

I just started programming using C++. I face some problem during execution of ifstream in loop.
do
{
system("cls");
inFile.open ("Account_Details.txt");
while (!inFile.eof())
{
getline (inFile, line);
cout << line << endl;
}
inFile.close();
cin.ignore(100, '\n');
cin >> choice;
}
while (choice != '1' && choice != '2');
This is part of my code. When the loop run, it doesnt show data in the txt file.
Thanks for any help. ^^

add infile.clear() after the infile.close() - the eof bits are not cleared by the close

There is a chance that the file doesn't exist. If that's the case, it will create an empty file. Check the path of the file.

I have been writing C++ code for close to 10 years. During that time I have learnt how to use C++ in a way that minimizes the number of errors (bugs) I create. Probably some will disagree with me, but I would recommend you to only use for and while to do looping. Never do-while. Learn these two well and you will be able to loop successfully any time you want.
To illustrate my technique, I have taken the liberty to rewrite your code using my style. It has complete error checking, uses a while loop with read-ahead, some C++0x, and simplified stream handling:
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
int main(int argc, char** argv)
{
// check program arguments
if (argc<2) {
std::cerr << "Usage: " << argv[0] << " file" << std::endl;
return EXIT_FAILURE;
}
// check file can be opened
std::ifstream infile(argv[1]);
if (!infile) {
std::cerr << "Failed to read " << argv[1] << std::endl;
return EXIT_FAILURE;
}
std::string input;
// read-ahead
std::getline(std::cin, input);
while (input!="q" && input!="quit" && input!="exit") {
//system("cls");
// print contents of file by streaming its read buffer
std::cout << infile.rdbuf();
// read file again
infile = std::ifstream(argv[1]);
// finally, read again to match read-ahead
std::getline(std::cin, input);
}
}
Save to main.cpp, compile to print.exe and run with print.exe main.cpp.
Good luck with learning C++!

Related

I am getting several errors in this section of my code in which I am trying to turn the output into capital letters

{
const char* fname = "myfile"; //or string fname ("str.txt") in C++11
string input; //our first look at the C++ string object
fstream myfile; //construct fstream object for file i/o
openfile(myfile, fname, ios_base::out); //open file for output (current contents lost)
std::transform(myfile.open(), myfile.end(), myfile.open(), ::toupper);
while (cout << "Enter a line ('q' to quit): " && getline(cin, input))
{
if (input == "q")
break;
else //exit while loop
myfile << input << endl; //pipe string we read file add new line character
}
myfile.close(); //close our file
std::transform(myfile.open(), myfile.end(), myfile.open(), ::toupper);
openfile(myfile, fname, ios_base::in); //reopen it for input
cout << "\nHere's whats in " << fname << ":\n";
while (getline(myfile, input)) //get and print all the lines
cout << input << endl;
system("pause");
}
Severity Code Description Project File Line Suppression State
Error (active) E0304 no instance of overloaded function "std::basic_fstream<_Elem, _Traits>::open [with _Elem=char, _Traits=std::char_traits<char>]" matches the argument list fileio2 C:\Users\burnsk\source\repos\Hello\fileio2\fileio2.cpp 14
Severity Code Description Project File Line Suppression State
Error (active) E0109 expression preceding parentheses of apparent call must have (pointer-to-) function type fileio2 C:\Users\burnsk\source\repos\Hello\fileio2\fileio2.cpp 14
std::transform(myfile.open()
That's not going to work. std::transform expects an input iterator range, typically some begin/end range. std::fstream::open doesn't return an iterator.
You probably want to look at std::istream_iterator<char>.
We'll do a quick code review of what you've posted. I've removed most of your comments, and we'll actually use that as our first critique. The comments don't help readability at all. You're just restating the line of code, which isn't a great comment. Comments that explain 'why' or fill in the information gaps that the code alone cannot explain are much better.
// Missing includes and main()
// This does not qualify as a Minimal, Reproducible Example
// Specifically, it's not reproducible, as it cannot be copy/pasted
// and ran by the people you want to get help from.
// https://stackoverflow.com/help/minimal-reproducible-example
{
const char* fname = "myfile"; // Hard-coded file name is meh, C-string also
string input; // Prefer this EVERYWHERE
fstream myfile;
openfile(myfile, fname, ios_base::out); // No explanation of this function
// It's not standard, you should
// have posted its code.
// Bad syntax, as explained. Refer to the documentation
// https://en.cppreference.com/w/cpp/algorithm/transform
std::transform(myfile.open(), myfile.end(), myfile.open(), ::toupper);
// Clever, but the user likely doesn't need to be prompted before
// every line. Instead, you could have checked for the end condition.
while (cout << "Enter a line ('q' to quit): " && getline(cin, input))
{
if (input == "q")
break; // This is the line that exits the loop
else //exit while loop
myfile << input << endl; // Premature write
}
myfile.close();
// See above about transform syntax being bad. But why write data
// you don't want, close the file, re-open the file, try to
// re-write the data, and close the file again?
std::transform(myfile.open(), myfile.end(), myfile.open(), ::toupper);
openfile(myfile, fname, ios_base::in); //reopen it for input
cout << "\nHere's whats in " << fname << ":\n";
while (getline(myfile, input)) //get and print all the lines
cout << input << endl;
system("pause");
}
Since you are reading the strings in, and not caring about the original contents, why not manipulate the string to look the way you want, and then write it to the file. It's a lot simpler.
My code below does that, and uses a few other tricks to avoid copy/pasta.
The biggest change is that the user is only told what to do once, and the while() loop Boolean expression grabs the line and ensures it's not the quit condition.
The string is then run through std::transform() and fully capitalized. And then it is written to the file. This writes the data we want one time, instead of writing a bunch of bad data and then doubling back and trying to fix it.
For printing the contents of the file to the screen, we create a new class that holds a string and changes how it can be read in, essentially reading an entire line at a time instead of a word. This is not necessary, but like I said, I put some stuff in to avoid a straight copy/paste/submit situation.
#include <algorithm>
#include <cctype>
#include <fstream>
#include <iostream>
#include <iterator>
#include <string>
namespace detail {
class Line {
std::string m_line;
public:
friend std::istream& operator>>(std::istream& sin, Line& line) {
std::getline(sin, line.m_line);
return sin;
}
operator std::string() const { return m_line; }
};
} // namespace detail
int main(int argc, char* argv[]) {
if (argc != 2) return 1;
std::ofstream fout(argv[1]);
if (!fout) {
std::cerr << "Error opening file for writing.\n";
return 2;
}
std::cout << "Type lines. Type \"q\" on its own line to quit.\n";
std::string line;
while (std::getline(std::cin, line) && line != "q") {
std::transform(line.begin(), line.end(), line.begin(),
[](const auto& c) { return std::toupper(c); });
fout << line << '\n';
}
fout.close();
std::ifstream fin(argv[1]);
if (!fin) {
std::cerr << "Error opening file for reading.\n";
return 3;
}
std::copy(std::istream_iterator<detail::Line>(fin),
std::istream_iterator<detail::Line>(),
std::ostream_iterator<std::string>(std::cout, "\n"));
fin.close();
}
Output:
❯ ./a.out text.txt
Type lines. Type "q" on its own line to quit.
You'll be back, time will tell
You'll remember that I served you well
Oceans rise, empires fall
We have seen each other through it all
And when push comes to shove
I will send a fully armed battalion to remind you of my love!
q
YOU'LL BE BACK, TIME WILL TELL
YOU'LL REMEMBER THAT I SERVED YOU WELL
OCEANS RISE, EMPIRES FALL
WE HAVE SEEN EACH OTHER THROUGH IT ALL
AND WHEN PUSH COMES TO SHOVE
I WILL SEND A FULLY ARMED BATTALION TO REMIND YOU OF MY LOVE!

Open a file with C++ and output the text that is in the file

I am trying to open a file with C++ and output the text that is in the file. I cannot seem to figure out what I am doing wrong. Here is what I have so far.
#include <iostream>
#include <string>
#include <fstream>
#include <cstdlib>
using namespace std;
int main()
{
char fileName[50];
ifstream infile;
cout << "Enter the name of the file you would like to open: ";
cin.getline(fileName, 50);
infile.open(fileName);
if(!infile.is_open())
{
exit(EXIT_FAILURE);
}
char line[75];
infile >> line;
while (infile.good())
{
cout << line << " ";
infile >> line;
}
system("pause");
return 0;
}
After I input the file name and press enter the CMD prompt just closes. I know that the file exist, but I cannot figure out why it is exiting. Obviously it is because of the exit command, but it should be open. What am I doing wrong?
You don't need to read/write the file line by line; C++ already supports to copy the file in one step. You also should use string instead of char[] for your strings; on one hand it means that you don't need to restrict the maximal length of your strings to some arbitrary length (what if your file's pathname has more than 50 characters, or the file has lines with more than 75 characters?
Note also that your file copying code is erroneous: It will remove all whitespace from the file, as infile >> line does not read a line (use readline for that), but a word, discarding whitespace.
Also, your code should give an error message if it couldn't open the file, instead of just silently returning (you do provide an error return, which is very good, but unless you call it from something that actually gives you feedback on the error return, you'll never learn about it.
Finally, the system("pause") should probably be done in an RAII class, so it is guaranteed to be exited on return (however, exit will not call destructors, so unless you want to use atexit, you should use return in `main`` instead). A better idea would, however, be to not put this into the code, but instead run it in a terminal that doesn't immediately close after the program finishes.
Here's a program that implements those suggestions:
#include <iostream>
#include <fstream>
#include <cstdlib>
int main()
{
// make sure that system("pause") is called on all exit paths
struct cleanup
{
~cleanup() { std::system("pause"); }
} do_cleanup;
// get the file name
std::string filename;
std::cout << "Enter the name of the file you would like to open: ";
std::getline(std::cin,filename);
if (!std::cin)
{
std::cerr << "Failed to read the file name.\n";
return EXIT_FAILURE;
}
// open the file
std::ifstream infile(filename.c_str());
if (!infile)
{
std::cerr << "Could not open file: " << filename << "\n";
return EXIT_FAILURE;
}
// print the file
std::cout << infile.rdbuf();
// close the file
infile.close();
if (!infile)
{
std::cerr << "Could not properly close file: " << filename << "\n";
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
There is no need to use a char[]. You've even #included string so just use that.
string fileName;
cout << "Enter the name of the file you would like to open: ";
cin >> fileName;
// or
// getline(cin, fileName);
ifstream infile(fileName);
if (infile.fail()) {
exit(EXIT_FAILURE);
}
string line;
while (infile >> line) {
cout << line << " ";
}
system("pause");
return 0;
I also modified a few things to make it a bit cleaner.
Thanks for the help. Yes the file was in the wrong folder. It was a newb oversight!

edit: trouble checking if file is empty or not, what am I doing wrong?

Edit: changed my question to be more accurate of the situation
I'm trying to open up a text file (create it if it doesnt exist,open it if it doesnt). It is the same input file as output.
ofstream oFile("goalsFile.txt");
fstream iFile("goalsFile.txt");
string goalsText;
string tempBuffer;
//int fileLength = 0;
bool empty = false;
if (oFile.is_open())
{
if (iFile.is_open())
{
iFile >> tempBuffer;
iFile.seekg(0, iFile.end);
size_t fileLength = iFile.tellg();
iFile.seekg(0, iFile.beg);
if (fileLength == 0)
{
cout << "Set a new goal\n" << "Goal Name:"; //if I end debugging her the file ends up being empty
getline(cin, goalSet);
oFile << goalSet;
oFile << ";";
cout << endl;
cout << "Goal Cost:";
getline(cin, tempBuffer);
goalCost = stoi(tempBuffer);
oFile << goalCost;
cout << endl;
}
}
}
Couple of issues. For one, if the file exist and has text within it, it still goes into the if loop that would normally ask me to set a new goal. I can't seem to figure out what's happening here.
The problem is simply that you are using buffered IO streams. Despite the fact that they reference the same file underneath, they have completely separate buffers.
// open the file for writing and erase existing contents.
std::ostream out(filename);
// open the now empty file for reading.
std::istream in(filename);
// write to out's buffer
out << "hello";
At this point, "hello" may not have been written to disk, the only guarantee is that it's in the output buffer of out. To force it to be written to disk you could use
out << std::endl; // new line + flush
out << std::flush; // just a flush
that means that we've committed our output to disk, but the input buffer is still untouched at this point, and so the file still appears to be empty.
In order for your input file to see what you've written to the output file, you'd need to use sync.
#include <iostream>
#include <fstream>
#include <string>
static const char* filename = "testfile.txt";
int main()
{
std::string hello;
{
std::ofstream out(filename);
std::ifstream in(filename);
out << "hello\n";
in >> hello;
std::cout << "unsync'd read got '" << hello << "'\n";
}
{
std::ofstream out(filename);
std::ifstream in(filename);
out << "hello\n";
out << std::flush;
in.sync();
in >> hello;
std::cout << "sync'd read got '" << hello << "'\n";
}
}
The next problem you'll run into trying to do this with buffered streams is the need to clear() the eof bit on the input stream every time more data is written to the file...
Try Boost::FileSystem::is_empty which test if your file is empty. I read somewhere that using fstream's is not a good way to test empty files.

getline() function in C++ does not work

i wrote a code in C++ where it opens a .txt file and reads its contents, think of it as a (MAC address database), each mac address is delimited by a (.), my problem is after i search the file for total number of lines , iam unable to return the pointer to the initial position of the file in here i use seekg() and tellg() to manipulate the pointer to the file.
here is the code:
#include <iostream>
#include <fstream>
#include <conio.h>
using namespace std;
int main ()
{
int i = 0;
string str1;
ifstream file;
file.open ("C:\\Users\\...\\Desktop\\MAC.txt");
//this section calculates the no. of lines
while (!file.eof() )
{
getline (file,str1);
for (int z =0 ; z<=15; z++)
if (str1[z] == '.')
i++;
}
file.seekg(0,ios::beg);
getline(file,str2);
cout << "the number of lines are " << i << endl;
cout << str2 << endl;
file.close();
getchar();
return 0;
}
and here is the contents of the MAC.txt file:
0090-d0f5-723a.
0090-d0f2-87hf.
b048-7aae-t5t5.
000e-f4e1-xxx2.
1c1d-678c-9db3.
0090-d0db-f923.
d85d-4cd3-a238.
1c1d-678c-235d.
here the the output of the code is supposed to be the first MAC address but it returns the last one .
file.seekg(0,ios::end);
I believe you wanted file.seekg(0,ios::beg); here.
Zero offset from the end (ios::end) is the end of the file. The read fails and you're left with the last value you read in the buffer.
Also, once you've reached eof, you should manually reset it with file.clear(); before you seek:
file.clear();
file.seekg(0,ios::beg);
getline(file,str2);
The error would have been easier to catch if you checked for errors when you perform file operations. See Kerrek SB's answer for examples.
Your code is making all sorts of mistakes. You never check any error states!
This is how it should go:
std::ifstream file("C:\\Users\\...\\Desktop\\MAC.txt");
for (std::string line; std::getline(file, line); )
// the loop exits when "file" is in an error state
{
/* whatever condition */ i++;
}
file.clear(); // reset error state
file.seekg(0, std::ios::beg); // rewind
std::string firstline;
if (!(std::getline(file, firstline)) { /* error */ }
std::cout << "The first line is: " << firstline << "\n";

Try-Catch Block For C++ File-IO Errors Not Working

I'm very new to the world of C++ error handling, but I was told here:
Checking for file existence in C++
...that the best way to checks for file existence was with a try-catch block. From my limited knowledge on the topic, this sounds like sound advice. I located this snippet of code:
http://www.java2s.com/Tutorial/Cpp/0240__File-Stream/Readafileintrycatchblock.htm
#include <fstream>
#include <iostream>
using namespace std;
int main ()
{
try{
char buffer[256];
ifstream myfile ("test.txt");
while (! myfile.eof() )
{
myfile.getline (buffer,100);
cout << buffer << endl;
}
}catch(...){
cout << "There was an error !\n";
}
return 0;
}
...but when I compile it using
g++ -Wall -pedantic -o test_prog main.cc
And run the program in a directory where test.txt does not exist, the prog keeps spitting out empty lines to the terminal. Can anyone figure out why?
Also is this a good way to check for file existence for a file you actually want to open and read from (versus just something where your indexing a bunch of files and checking them over)?
Thanks!
In C++ iostreams do not throw exeptions by default. What you need is
ifstream myfile("test.txt");
if(myfile) {
// We have one
}
else {
// we dont
}
By default the fstream objects do not throw. You need to use void exceptions ( iostate except ); to set the exception behavior. You can fetch the current settings using iostate exceptions ( ) const;. Change your code just a bit:
#include <fstream>
#include <iostream>
#include <stdexcept>
using namespace std;
int main ()
{
try{
char buffer[256];
ifstream myfile ("test.txt");
myfile.exceptions ( ifstream::eofbit | ifstream::failbit | ifstream::badbit );
while (myfile)
{
myfile.getline (buffer,100);
cout << buffer << endl;
}
myfile.close();
}catch(std::exception const& e){
cout << "There was an error: " << e.what() << endl;
}
return 0;
}
First of all, for the try block to do any good, you need to enable exceptions for the stream.
Second, a loop like:
while (! myfile.eof() )
Will lead to nothing but trouble, and you're seeing that here. The problem (in this case) is that when the file failed to open, eof will never be signaled -- you can't/don't reach the end of the file because there is no file. Therefore, your loop runs forever, on an existentialist search for the end of a nonexistent file. Fix the loop, and things get better in a hurry:
char buffer[256];
ifstream myfile ("test.txt");
while (myfile.getline(buffer,100))
{
cout << buffer << endl;
}
While you're at it, a bit more fixing wouldn't hurt (unless you really meant to use less than half of the space you allocated for your buffer):
char buffer[256];
ifstream myfile ("test.txt");
while (myfile.getline(buffer,sizeof(buffer)))
{
cout << buffer << endl;
}
Or, of course, eliminate the problem entirely:
std::string buffer;
ifstream myfile("test.txt");
while (getline(myfile, buffer))
cout << buffer << "\n";
Edit: note that none of these (at least currently) depends on exceptions at all. They're all set up to write a line to the output if we succeeded in our attempt at reading a line from the input. If the file didn't open, the body of the loop simply won't execute, because we won't be able to read from a file that didn't open. If we want to print an error message telling the user that the file didn't open, we'd have to handle that separately from what's above. For example:
ifstream myfile("test.txt");
if (!myfile) {
std::cerr << "File failed to open";
return FAIL;
}
while (std::getline(myfile // ...