I Can't print out a file that I wrote on - c++

I have created a function to write some data on a text file, and it works fine. I created another function to read in all the content of the file, and print it out for me! But, it is not working for some reason. Could any one help please?
This is my function:
void myClass::displayFile() {
char line[LINE]; //to hold the current line
file.open("data.txt", ios::app);
//keep reading information from the file while the file is open and has data
while (!file.fail() && !file.eof()) {
int lineSize; //to loope through each line
file.getline(line, LINE);
lineSize = strlen(line);
//loop through the line to print it without delimiters
for (int i = 0; i < lineSize; ++i) {
if (line[i] == ';') {
cout << " || ";
} else {
cout << line[i];
}
}
}
file.close();
file.clear();
if (file.fail()) {
cerr << "Something went wrong with the file!";
}
}
Note: The function compiles and the loop is accessible, but the line string is empty.
This is the writing function:
void myClass::fileWriter() {
file.open("data.txt", ios::app);
file << name << ";" << age << ";" << "\n";
file.close();
file.clear();
}

Silly me, the cause of your problem was staring me right in the face from the beginning, and it's the app open-mode that's the problem. It is to open the file in write mode, which means you can't read from it.
And even if you could read from the file, the cursor is placed ad the end of the file the eofbit flag would have been set inside the first iteration anyway.
If you want to read from a file, then either use std::ifstream which automatically sets the in mode if you don't specify a mode, or you have to explicitly set the in mode when opening.

Related

Editing a text file if searched value is present

I have just a couple issues here with my code. It works but I'm not advanced enough to do what I want to yet. Nor do I know how to word it for a google search. I have a Blackjack game that I'm doing and want to know how to edit certain lines of the file depending on user input. Simpler, I want a user to be able to open the game and start with their balance from the last time they were playing(a save and load feature). My issues are the balance and the username are on the same line in the text file (purposefully) and I want to assign the variables to those in the text file. I know I'm on the right track, I just dont know where to go from here. Thanks for the help in advance. If I broke a rule of posting, I'm sorry.
input username
if username is present in file
edit balance on leave
if username isnt present in file
create new user
Here is my code for the load function:
void load(userAcc user1)
{
ifstream in;
in.open("Balances.txt");
if (in.is_open())
{
string word;
for (int x = 0; in >> word; x++);
{
user1.name = word;
user1.balance = word;
}
cout << user1.name << endl;
cout << user1.balance << endl;
in.close();
}
else
cout << "Cannot open a file";
}
void save(userAcc user1)
{
user1.balance = "1000";
cout << "Enter a username: ";
cin >> user1.name;
ofstream out;
out.open("Balances.txt", ios_base::app);
if (out.is_open())
{
out << user1.name << " " << user1.balance << endl;
out.close();
}
else
cout << "Cannot open a file";
}
In
for (int x = 0; in >> word; x++);
remove the trailing ;. It ends the statement before the body of the for loop, separating the two. The for spins around doing nothing but reading the file until it ends and incrementing the unused variable x and the following code block will be run exactly once, storing whatever is in word (and since the loop will exit when the read into word fails, what's in word will depend on the C++ Standard version the the compiler's been set to use) into user1.
Once the ; is removed, the for loop will read into word until no more words can be read from the file. Every word read is copied into the same userAcc writing over the previous word. When the file hits the end in >> word will fail and the loop will exit. The last word in the file will then be printed out, all other words having been overwritten.
Naïve fixing of this would look something like
void load(userAcc user1)
{
ifstream in;
in.open("Balances.txt");
if (in.is_open())
{
while (in >> user1.name // read name in from file
>> user1.balance) // read balance in from file
{ // loop will exit when it cannot read a name and a balance from the file
// for now we're just printing out what's read from the file.
cout << user1.name << endl << user1.balance << endl;
}
// in.close(); not needed. File will automatically close when in goes out of scope.
}
else
cout << "Cannot open a file";
}
But we probably want to do more than print out all of the users in the file, so let's put them into a convenient resizable container like std::vector.
vector<userAcc> load() // takes no parameters, returns list of accounts
{
vector<userAcc> accounts;
ifstream in;
in.open("Balances.txt");
if (in.is_open())
{
userAcc user1; // account we can read into
while (in >> user1.name >> user1.balance)
{
accounts.push_back(user1); // store account
}
}
else
cout << "Cannot open a file";
return accounts; // hand accounts read back to caller.
}
Use of the function would be something like
vector<userAcc> accounts = load();
The save function looks pretty much good-to-go as written.

C++: std::ofstream method open() wipes open ifstream file on second iteration

I am trying to build a "fileUpdater" which will copy an original file into multiple directories, where a file with the same name and extension was previously found.
bool update_files(const string inputPath, const vector<string> outputPaths)
{
ifstream src(inputPath);
if(!src.is_open())
{
cout << "Unable to open input file\n" << inputPath <<endl;
return false;
}
else
{
ofstream dst;
for(unsigned int i=0; i<= outputPaths.size()-1; i++)
{
dst.open(outputPaths[i]);
try
{
dst << src.rdbuf();
dst.close();
}
catch(int e)
{
cout << "Unable to replace file\n" <<endl;
cout << outputPaths[i] <<"\n"<< endl;
cout << "Error code: " <<e<<endl;
}
}
};
src.close();
return true;
}
Exactly after executing
dst.open(outputPaths[i]);
in the second iteration, the original file opened by
ifstream src(inputPath);
gets wiped and only an empty file is copied into the remaining directories.
I also tried
dst.clear();
dst.close();
and
src.clear();
src.seekg(0,ios::beg);
before entering the next iteration, but it made no difference.
UPDATE
After trying different files, I realised the behavior depends on the input file. Above behavior appeared for .m-files (MatLab).
After testing it with .txt files, all files were wiped.
The way you're copying the file, with dst << src.rdbuf();, will leave the current file position at the end of your input file. On the second iteration, that same read won't read anything (leaving an empty copy of the file) because you're already at the end of the input file.
The solution is to seek back to the beginning of the input file before every read, using seekg. You should call tellg before reading anything (right after opening the file), then seek to that position.
auto startpos = src.tellg();
ofstream dst;
// ...
src.seekg(startpos);
dst << src.rdbuf();
None of the proposed methods work.
Neither resetting the pointer, nor pulling ifstream into the loop, which would result in opening the input file (which is not supposed to change) unnecessarily often.
It is still unclear why dst.open(outputPaths[i]); is wiping the input file. Also the exact moment of the wipe depends on used types of files.
I implemented following workaround, effectively reading the input file into a string and closing it beforehand, in order to protect it from further read/write action.
bool update_files( const string inputPath, const vector<string> outputPaths)
{
const char * in = inputPath.c_str();
ifstream src(in);
if(!src.is_open())
{
cout << "Unable to open input file\n" << inputPath <<endl;
return false;
}
else
{
string buffer;
streamsize s=src.gcount();
src.seekg(0,ios::end);
buffer.reserve(src.tellg());
src.seekg(0,ios::beg);
buffer.assign((istreambuf_iterator<char>(src)), istreambuf_iterator<char>());
src.close();
for(unsigned int i=0; i<= outputPaths.size()-1; i++)
{
const char * out = outputPaths[i].c_str();
ofstream dst(out);
try
{
dst << buffer;
dst.close();
}
catch(int e)
{
cout << "Unable to replace file\n" <<endl;
cout << outputPaths[i] <<"\n"<< endl;
cout << "Error code: " <<e<<endl;
}
}
};
src.close();
return true;
}

Error opening a text file using ifstream c++11

I am creating an object called SpellChecker that corrects the spelling of words in a string.
To check if the words are spelled correctly and if not to correct them, I have a text file of correct words (one per line). I also have a text file of words that are misspelled and their corrections separated by a tab.
My issue is reading in my text file. I have created an if statement to see if my file opens successfully. However, I believe my file should be readable and it is not. I am trying to find out why this is happening.
Here is my SpellChecker constructor:
SpellChecker::SpellChecker(string tempLanguage, string correctWordsFile,string wordCorectionsFile){
language=tempLanguage;
ifstream istream;
istream.open(correctWordsFile);
if(!istream.is_open()){
cout << "Error opening " << correctWordsFile << endl;
}
int count=0;
string temp;
while(!istream.eof()){
getline(istream,temp);
correctWords[count] = temp;
count++;
}
numCorrectWords = count;
istream.close();
istream.open(wordCorectionsFile);
if(!istream.is_open()){
cout << "Error opening " << wordCorectionsFile << endl;
}
int j=0;
int i=0;
char temp2;
while(!istream.eof()){
istream.get(temp2);
if(temp2 == '\t'){
j++;
}
else if(temp2 == '\n'){
i++;
j = 0;
}
else
wordCorections[i][j] += temp2;
}
numwordCorrections = i;
istream.close();
}
Here is my main:
int main(){
SpellChecker spellCheck("English","CorectWords.txt","WordCorections.txt");
spellCheck.viewCorrectWords();
spellCheck.viewCorrectedWords();
spellCheck.setEnd('~');
spellCheck.setStart('~');
cout << spellCheck.repair("I like to eat candy. It is greatt.");
}
The terminal returns:
"Error opening CorectWords.txt"
How can I solve this problem?
The call to library function is_open() is returning false, which could be due to one of many reasons.
Ensure that :
1. You have used correct name of the data file.
2. The data file is in the same folder as the executable of your program.
3. It has been closed by any previous program that read it.

Writing to file results in empty file

I wrote a small program that opens a file, builds a vector from every line in the file and then have the user able to add/remove from the file. The program first removes from the vector, then rebuilds the file based on the vector. Here's the code that rebuilds the file (fileName is a member variable with the full name of the text file, ex. "test.txt":
bool rebuildFile() {
if (remove(fileName.c_str()) == 0) { // remove the old file
ofstream newFile(fileName); // create new file with same name
newFile.open(fileName, ios::app); // open to append to end of file
if (newFile.is_open()) {
newFile << fileHeader << endl; // add the first header line
for (int i = 0; i < myVector.size(); i++) { // loop through vector, adding strings to file
newFile << myVector[i] << endl; // I used "\n" instead of endl, but both give same results
}
newFile.close();
return true; // success
}
}
return false; // failure
}
After this function exits, the file is completely empty. So it clearly creates a new file, but then the writing part is an issue, and I can't figure out why. I read other posts where some had issues where they had the file open in Notepad/Notepad++, but I've always made sure to close that specific file before running the program. I'm not sure if the ios::app flag is causing an issue with the loop, but the documentation seems clear that it just points to the end of the file every time you output to it, so I don't think the issue is there. Any thoughts?
EDIT:
Apparently you can't append to an empty file... This new code works, but I'm not sure if there's a "cleaner" way to add to a file in two different ways without opening and closing it twice using different flags.
new code:
bool rebuildFile() {
if (remove(fileName.c_str()) == 0) {
std::ofstream newFile(fileName);
newFile.open(fileName);
if (newFile.is_open()) {
newFile << fileHeader << endl;
newFile.close();
}
newFile.open(fileName, std::ofstream::out | std::ofstream::app);
if (newFile.is_open()) {
for (int i = 0; i < myVector.size(); i++) {
newFile << myVector[i] << endl;
}
newFile.close();
return true;
}
}
return false;
}
Trying to call open on an already open file stream puts the stream in a failed state.
Just change
ofstream newFile(fileName); // create new file with same name
newFile.open(fileName, ios::app);
to
ofstream newFile(fileName, ios::app);
[ofstream.members]
void open(const char* s, ios_base::openmode mode = ios_base::out);
Effects: Calls rdbuf()->open(s, mode | ios_base::out). If that
function does not return a null pointer calls clear(), otherwise calls
setstate(failbit) (which may throw ios_base::failure (27.5.5.4)).
[filebuf.members]
basic_filebuf<charT,traits>* open(const char* s, ios_base::openmode mode);
Effects: If is_open() != false, returns a null pointer. [...]
bool is_open() const;
Returns: true if a previous call to open succeeded (returned a
non-null value) and there has been no intervening call to close.
ofstream newFile(fileName);
doesn't just create the file, it opens it too. And that means you can't open it again.
I don't see a reason to remove the file, re-create it - truncating if it exists - and open it, write a little, close the file, open it again but for appending, and then write to it some more.
Plus, if you run out of luck, there's an opportunity for a different process to modify (or delete) the file between the first close and the second open, which is in general not a good thing.
This snippet should work:
bool rebuildFile()
{
std::ofstream newFile(fileName);
if (newFile)
{
newFile << fileHeader << endl;
for (int i = 0; i < myVector.size(); i++) {
newFile << myVector[i] << endl;
}
}
return newFile;
}
(Files are closed automatically, if needed, by ofstream's destructor.)

To split a large data file into several small files (text format)

I am trying to split a large data file into several small text files. The following code opens and closes a new file every time, which is not feasible. Is there an alternative way of doing this?
ifstream infile(file_name);
if(infile)
{
char val;
while(!infile.eof())
{
ofstream ofile (ofile_name);
infile >> val;
ofile << val;
if( infile.peek() == '\n' )// last entry on the line has been read
{
row_counter++;
if (row_counter == win_size)
// generate new ofile_name
}
ofile.close();
}
infile.close();
}
You will not be able to create several output files without opening and closing the output files.
The reason is, that each output file should have a unique name. You will have to generate useful names for the output files. The connection between the file (content) and the file name will be done in the open call (or ofstream constructor).
Edit
To avoid open and close for each character you need status variable. In your example row_counter is usable for it. You need following steps:
open initial ofile before your while(!infile.eof()) loop
close your ofile, generate next name and open the new where where you wrote // generate new ofile_name
finally close your ofile after the loop.
This could be done in this way:
if(infile)
{
char val;
row_counter = 0;
ofstream ofile (ofile_name);
while(!infile.eof())
{
infile >> val;
ofile << val;
if( infile.peek() == '\n' )// last entry on the line has been read
{
row_counter++;
if (row_counter == win_size)
{
row_counter = 0;
ofile.close();
// generate new ofile_name
ofile.open(ofile_name); // you might change the nMode parameter if necessary
}
}
}
ofile.close();
infile.close();
}