questions on how to open text file properly in c++ programming - c++

first time here. I am a student doing some c++ coding for end year project. The programme that I coded does not read the text file even though everything seems to be in order. Some helps would be fantastic!
void transactionRecords(double total, char answer, string nameT, int HpNo, string address)
{
fstream myFile;
string name;
char idStatus;
double amt, sumAll=0;
myFile.open("transaction.txt",fstream::in);
if (!myFile) cout<<"Unable to Open File under Input Mode";
else
{
while (!myFile.eof())
{
myFile>>name>>idStatus>>address>>HpNo>>amt;
if (myFile.fail()) break;
}
myFile.close();
myFile.open("transaction.txt",fstream::app);
if (!myFile) cout<<"Unable to Open File under App Mode";
else
{
myFile<<nameT<<" "<<answer<<" "<<address<<" "<<HpNo<<" "<<total<<endl;
if (myFile.fail()) cout<<"Error encountered while adding data!\n";
}
}
myFile.close();
}
this is whats in the text file
Johns Y pasir_ris 81231211 4.14

First, I suggest you use the RAII principle when creating files that is:
void myfunction() {
ifstream f{"file.txt"};
// your logic here
// NB -- no need to manually close file, prevents resource leaks
}
There is no need to manually close or open such a file, it is opened by the constructor and closed when the destructor is invoked upon exiting the current scope. This prevents leaks of file handles and is a pervasive technique in C++.
Second, use the standard stream read loop in C++:
while (myFile>>name>>idStatus>>address>>HpNo>>amt) {
// your logic here, the read has succeded
// TODO process myFile, name, idStatus etc.
}
With these changes, your example should look something like:
void transactionRecords(double total, char answer, string nameT, int HpNo, string address)
{
ifstream myFile{"transaction.txt"};
string name;
char idStatus;
double amt, sumAll=0;
if (!myFile) cout<<"Unable to Open File under Input Mode";
return;
while (myFile>>name>>idStatus>>address>>HpNo>>amt) {
// TODO do something here??
}
ofstream tFile{"transaction.txt"};
if (!myFile) cout<<"Unable to Open File under App Mode";
return;
if (!(tFile<<nameT<<" "<<answer<<" "<<address<<" "<<HpNo<<" "<<total<<endl)) {
cout<<"Error encountered while adding data!\n";
}
}
}
You should probably do something in the TODO block, currently you are only storing the last values read? If you only mean to process one line from the file, swap the while loop with an if.

Related

How to make filestream check for duplicate appends?

So, I'm coding for a C++ program (well, actually a .dll plugin for RpgMaker 2003), and I have a code like this:
#include <DynRPG/DynRPG.h>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
std::map<std::string, std::string> configuration;
bool onStartup(char *pluginName) {
// We load the configuration from the DynRPG.ini file here
configuration = RPG::loadConfiguration(pluginName);
return true; // Don't forget to return true so that the start of the game will continue!
}
bool onComment( const char* text,
const RPG::ParsedCommentData* parsedData,
RPG::EventScriptLine* nextScriptLine,
RPG::EventScriptData* scriptData,
int eventId,
int pageId,
int lineId,
int* nextLineId )
{
std::string cmd = parsedData->command;
std::string filecode;
std::string scanfile;
string FileName;
if(!cmd.compare("file_string")) //new code
{
ofstream myfile;
myfile.open ("dynstore.txt", ios::app);
myfile << parsedData->parameters[0].text << "\n";
myfile.close();
return false;
}
if(!cmd.compare("store_file")) //new code
{
ofstream myfile;
myfile.open ("dynstore.txt", ios::app);
myfile << RPG::actors[parsedData->parameters[0].number]->name << "\n";
myfile.close();
return false;
}
if(!cmd.compare("load_file")) //new code
{
ifstream myfile;
myfile.open ("dynstore.txt");
if(myfile.good()) //this should skip if the file doesn't exist.
{
getline (myfile, filecode);
RPG::actors[parsedData->parameters[0].number]->name = filecode;
}
myfile.close();
return false;
}
//These first three allow only storage using dynstore.
if(!cmd.compare("create_file")) //custom file name, plus storing text
{
FileName = parsedData->parameters[0].text;
ofstream myfile;
myfile.open (FileName.c_str(), ios::app);
myfile << parsedData->parameters[1].text << "\n";
myfile.close();
return false;
}
//This stores a word and makes a new line
if(!cmd.compare("create_save")) //custom file name, plus storing text
{
int GameFile = RPG::variables[3351];
ofstream myfile;
if(GameFile == 0)
{
FileName = parsedData->parameters[0].text;
myfile.open (FileName.c_str(), ios::app);
}
if(GameFile == 1)
{
myfile.open ("Save01.txt", ios::app);
}
if(GameFile == 2)
{
myfile.open ("Save02.txt", ios::app);
}
if(GameFile == 3)
{
myfile.open ("Save03.txt", ios::app);
}
if(GameFile == 4)
{
myfile.open ("Save04.txt", ios::app);
}
if(GameFile == 5)
{
myfile.open ("Save05.txt", ios::app);
}
if(GameFile == 6)
{
myfile.open ("Save06.txt", ios::app);
}
myfile << parsedData->parameters[1].text << "\n";
myfile.close();
return false;
}
//This stores a word and makes a new line
if(!cmd.compare("make_file")) //custom file name, plus storing text
{
FileName = parsedData->parameters[0].text;
ofstream myfile;
myfile.open (FileName.c_str(), ios::app);
myfile << RPG::actors[parsedData->parameters[1].number]->name;
myfile.close();
return false;
}
//This stores a name
if(!cmd.compare("read_file")) //sets data info to name for easy read
{
FileName = parsedData->parameters[0].text;
ifstream myfile;
myfile.open (FileName.c_str());
if(myfile.good()) //this should skip if the file doesn't exist.
{
getline (myfile, filecode);
RPG::actors[parsedData->parameters[1].number]->name = filecode;
}
myfile.close();
return false;
}
if(!cmd.compare("clear_file")) //sets data info to name for easy read
{
FileName = parsedData->parameters[0].text;
ofstream myfile;
myfile.open (FileName.c_str());
myfile.clear();
myfile.close();
return false;
}
if(!cmd.compare("scan_save"))
{
//Attempt ONE to scan the file for a string
//this one works by turning on a switch if the string is found
int GameFile = RPG::variables[3351];
ifstream myfile;
if(GameFile == 0)
{
FileName = parsedData->parameters[0].text;
myfile.open (FileName.c_str());
}
if(GameFile == 1)
{
myfile.open ("Save01.txt");
}
if(GameFile == 2)
{
myfile.open ("Save02.txt");
}
if(GameFile == 3)
{
myfile.open ("Save03.txt");
}
if(GameFile == 4)
{
myfile.open ("Save04.txt");
}
if(GameFile == 5)
{
myfile.open ("Save05.txt");
}
if(GameFile == 6)
{
myfile.open ("Save06.txt");
}
scanfile = parsedData->parameters[1].text;
int switchnum = parsedData->parameters[2].number;
if(myfile.good()) //this should skip if the file doesn't exist.
{
for(std::string temp;!myfile.eof();std::getline(myfile,temp))
{
if(temp.find(scanfile)!=std::string::npos)
{
RPG::switches[switchnum] = true;
//Turns on the switch if the string has been found in the file
//ideally, I'd want to save a new name using the scanfile, but I can't figure out how to copy it
}
}
}
myfile.close();
return false;
} //This checks only the current save, defaulting to the input if none exists
if(!cmd.compare("scan_file"))
{
//Attempt ONE to scan the file for a string
//this one works by turning on a switch if the string is found
FileName = parsedData->parameters[0].text;
ifstream myfile;
myfile.open (FileName.c_str());
scanfile = parsedData->parameters[1].text;
int switchnum = parsedData->parameters[2].number;
if(myfile.good()) //this should skip if the file doesn't exist.
{
for(std::string temp;!myfile.eof();std::getline(myfile,temp))
{
if(temp.find(scanfile)!=std::string::npos)
{
RPG::switches[switchnum] = true;
//Turns on the switch if the string has been found in the file
//ideally, I'd want to save a new name using the scanfile, but I can't figure out how to copy it
}
}
}
myfile.close();
return false;
}
if(!cmd.compare("file_good"))
{
//Checks for the existence of a file.
FileName = parsedData->parameters[0].text;
ifstream myfile;
myfile.open (FileName.c_str());
int switchnum = parsedData->parameters[1].number;
if(myfile.good()) //this should skip if the file doesn't exist.
{
RPG::switches[switchnum] = true;
}
else
{
RPG::switches[switchnum] = false;
}
myfile.close();
return false;
}
//End of cmd
return true;
}
Generally, this is how the .dll plugin works: It runs the DynRPG headers through the linker settings, and the RPG_RT.exe of RpgMaker as its host arguments. onStartup and onComment are DynRPG-specific codes to run compatibly with RpgMaker. You don't need to know most of this, except to know that these if(!cmd.compare(" ")) codes basically are commands for RpgMaker. So, I am telling various files to open text files, but I've been having problems:
I have a code to clear file, and it does clear the file. But I think
it creates the file in order to clear it, rather than skipping over
if it doesn't exist. In fact, I think this is a persistent issue, I
dunno how to get the code to skip over nonexistent file names, so it
makes new files if the code checks files.
If possible, that clear file should actually delete the files rather
than just making it blank.
It appends information into the file I make (and there doesn't seem
to be any memory leak), but it doesn't check to make sure that I
haven't already entered the same word or phrase. When I'm writing
into the file, I want to check But I think I only know how to check
output when loading output, not before input. I want to avoid
duplicates. Currently, I have a file called "awards.txt" (unlockable
awards) and I have the file with like 6 instances of the same word.
I want it to write the same code only once. This is my main problem.
Don't give obtuse advice, assuming I will understand what you mean. Show me actual code. I barely pieced together this much code from reading and adapting other tutorials, and I do not have a degree in computer science (I was a history major, so the theory of C++ code doesn't always make sense to me). Oh and uhhhh, not all the header files are necessary, I tend to include more than I need just in case.
Point 1
In
if(!cmd.compare("clear_file")) //sets data info to name for easy read
{
FileName = parsedData->parameters[0].text;
ofstream myfile;
myfile.open (FileName.c_str());
myfile.clear();
myfile.close();
return false;
}
the default file open mode used in myfile.open (FileName.c_str()); will create an empty file, overwriting an exiting file. Cool. Empty file is what you wanted, but yeah, it created an empty file where none existed. To avoid that, you'd need to specify an open mode that won't create a new file. Using this groovy table here, specifying the in open mode will raise an error if the file doesn't exit rather than opening it. Unfortunately if you keep reading you'll find there is no combination of openmodes that will truncate (clear) a file without also creating a new file.
Well doesn't that suck?
In C++17 we can use the <filesystem> Library's resize_file function.
std::error_code code;
std::filesystem::resize_file(FileName, 0, code);
// test code here if you care. Someone else could have the file open and prevent clearing.
Before C++17, its easiest to use system-specific API calls. You mention DLL above, so I'm going to assume a Windows target
HANDLE h = CreateFileA(FileName.c_str(),
GENERIC_WRITE,
0,
NULL,
TRUNCATE_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (h != INVALID_HANDLE_VALUE)
{
CloseHandle(h);
}
Documentation on CreateFileA. Note I use CreateFileA and not CreateFileW or CreateFile because FileName doesn't contain wide characters.
There might be a more direct call. I'm not really that familiar with the Win132 API.
A POSIX compliant target like Linux (Maybe Mac. I know even less about Macs) uses truncate
int code = truncate(FileName.c_str(), 0);
// test code here and look at errno if you care. Someone else could have the file open.
If you're lucky the compiler developers ported truncate to Windows for you and simplify your job because you only have to support one target.
Side note
Because the openmode was what's actually clearing the file, we should take a look at what myfile.clear(); does: clears error flags on a stream. Normally when a stream operation fails error flags are set so you can check to see what went wrong. When any error flags are set, the stream refuses to process any further transactions and instantly returns. It's on you-the-programmer to check the state of the stream after every transaction to ensure that it worked because if it didn't and you don't check, you'll never know. The stream state and error flags are the ONLY warning you get.
So, you check the flags, handle the flagged error, and then call clear to signal you've resolved the issue and are ready to get back to reading and writing. Note: Sometimes handling the error requires you to clear the flag early in order to remove, read out, bad data so that the program doesn't immediately find the same garbage and fail again once you return to the regular flow of the code.
Point 2
Deleting a file... Now that's easier. In C++17
std::error_code code;
std::filesystem::remove("test", code);
// Wrap in an if and test code if you care about failure. I would.
// If it's file not found, cool!
And in the old world,
if (remove(FileName.c_str()) !=)
{
//check errno to find out why
}
Documentation for std::filesystem::remove
Documentation for remove
Point 3
I just saw the time and I need to stop. You should remove point three from the question since it is a completely different issue and deserves its own question.

Opening file to read structure array

I'm a beginner in computer science learning c++.
Every attempt that I make to open a file in my program and read the information into a structure does not work.
Here is what I have written in the function.
void getMemberInfo(Payment member[])
{
ifstream file;
file.open("information.txt", ios::in);
int i = 0;
if (!file)
cout << "\n Error opening file!\n\n";
else
{
while (!file)
{
file >> member[i].ID;
file.getline(member[i].name, 30, '\n');
member[i].member_name = member[i].name;
file >> member[i].payment_due;
i++;
if (file.eof())
break;
}
}
file.close();
}
Any help is appreciated. I'm kind of at a loss of what's wrong.
The error is in the while condition. Just change the condition and it should work
// Instead of !file, use !file.eof()
while (!file.eof())

find word in a text in C++ and print some next specific lines

I wrote a code in C++ that writes a .txt file.
Then I want to open the code again and give some information, so I can get a new text depending on what I gave as an input.
For example I want to give the name of a month, and print in another .txt file all the lines that came after the word "November".
I found some solutions, but none of them worked for me!
One solution that I found on stack overflow is the following:
void Keyword(ifstream & stream, string token) {
string line;
while (getline(stream, line)) {
if (line.find(token) != string::npos) {
cout << line << endl;
}
}
cout << token << " not found" << endl;
}
I can't print the next lines with the code above.
Any suggestion would be helpful!
Thanks!
If you want to perform operations on files such as 'Read' and/or 'Write',you might want to search on the net(or if you have a C++ book) on topics such as "File I/O operations using C++". Anyways moving on, C++ has 2 basic classes to handle files which are ifstream and ofstream. And to use them you have to include ethier the header fstream(i.e #include<fstream>) or include them separately as #include<ifstream> and #include<ofstream>. ifstream is basically used for all input operations such as reading files etc. Similarly ofstream is used for all output operations such as writing data to files.
You can open a file and write data to it by doing the following,
ofstream myFile("filename");// Create an instance of ofstream and open file for writing data
and to write data to the file use the << operator like below,
myFile<<data;
Similarly, You can open a file and read data as follows,
ifstream myFile("filename");//Create an instance of ifstream and open file to read data
and to read data from the file use the >> operator as shown below,
myFile>>data;
You can also open a file using the method void open(const char *filename, ios::openmode mode); as shown below,
//Writing only
ofstream outFile;
outFile.open("filename.txt",ios::out);
//Reading only
ifstream inFile;
inFile.open("filename.txt",ios::in);
//For reading and writing
fstream file;
file.open("filename.txt",ios::in|ios::out);
//For closing File
outFile.close();
//or
inFile.close();
//or
file.close();
Note the open() method takes various flags such as ios::in for reading mode, ios::out for writing mode, ios::app for adding data to the end etc.
All of these can also combined by using the bit OR operator | as shown below,
outFile.open("filename.txt",ios::out|ios::app);
There is a lot more in IO. I just covered the things required to start.
Here is the solution to your problem. Try to understand it.
#include<iostream>
#include<fstream>
#include<cstring>
using namespace std;
int main()
{
ofstream outFile;
ifstream inFile;
char fileName[10],data[50];
int noLines;
cout<<"Enter Month:"<<endl;
cin>>fileName;
cout<<"Enter Number of lines you want to enter:"<<endl;
cin>>noLines;
outFile.open(fileName,ios::out);
cout<<fileName<<"(Enter Data):";
for(int i=0;i<=noLines;i++)
{
cin.getline(data,50);
outFile<<data<<endl;
}
outFile.close();
cout<<"Openening "<<fileName<<" :"<<endl;
inFile.open(fileName,ios::in);
for(int i=0 ;i<=noLines ;i++)
{
inFile.getline(data,50);
cout<<data<<endl;
}
inFile.close();
return 0;
}
OP has found most of the solution already:
string line;
while (getline(stream, line)) {
if (line.find(token) != string::npos) {
cout << line << endl;
}
}
cout << token << " not found" << endl;
But this only prints the lines with the keyword. And always prints the "not found" message. Ooops.
Instead I pitch:
string line;
bool found = false;
while (!found && getline(stream, line))
{ // search for keyword
if (line.find(token) != string::npos)
{
found = true; // found keyword. Stop looking
}
}
if (found)
{ // print out all remaining lines in the file
while (getline(stream, line))
{
cout << line << endl;
}
}
else
{
cout << token << " not found" << endl;
}
The above splits the finding of the token and the printing of the remaining file into two stages for readability. It can be compressed into one loop, but two things make this a sucker bet:
this program will be IO bound. It will spend the vast majority of its time reading the file, so little tweaks that do not address getting the file into memory are wasted time.
combining the loops would require the addition of logic to the loop that would, over along run, dwarf the minuscule cost of switching loops.
Try this:
http://www.cplusplus.com/doc/tutorial/files/
and this:
http://www.cplusplus.com/forum/beginner/14975/
It's about reading and writing files in c++ and about searching in files.

C++ Trouble opening a file for output

So I am working on a program for class in which we have to open two different text files to retrieve the appropriate text to be displayed in the console. My code is not opening the file and keeps outputting the else statement ".txt file cannot be open". I've tried several different ways to open the file but with no luck. Any help here would be greatly appreciated.
//
// main.cpp
// PunchLine program
// Page 896 Problem 3
//
//
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
//File stream objects
fstream inFile;
string line;
//Open joke file to read lines to console
inFile.open("joke.txt", ios::in);
if (inFile.is_open())
{
//Read lines from file to console
while (getline(inFile, line))
{
cout << line << endl;
inFile.close();
}
}
else
cout << "joke.txt file cannot be open.\n";
//Open punchline file to read last line joke to console
inFile.open("punchline.txt", ios::in);
if (inFile.is_open())
{
//Read last line from file to console
inFile.seekp(-52L, ios::end);
getline(inFile, line);
}
else
cout << "punchline.txt file cannot be open.\n";
return 0;
}
When declaring an input file use
ifstream inFile;
Also make sure the input file is in the same folder as your .exe
Edit: http://www.cplusplus.com/doc/tutorial/files/ also, this link should help with working with files.
Edit 2: I already posted this in a comment, but I'll just add it to the official answer: "Change your while loop as well. Instead of the if test, use while(inFile.is_open()) and then use your getline statement inside the loop. Because right now your code reads like while get this line from the file is true cout line. So it might not even be doing the while loop."
I don't think you should close the file inside the while loop. Otherwise, your file gets closed after only the first line is read in. Move the close statement outside the loop. Same for the second block.
if (inFile.is_open())
{
//Read lines from file to console
while (getline(inFile, line))
{
cout << line << endl;
}
inFile.close();
}
else
cout << "joke.txt file cannot be open.\n";
Check that your file exist. If it does, check whether you have the correct path when you open it (check if your .txt files are in the same directory as your .exe file, or specify the full path in your code). If yes, check if the files are read-only.
use
if(!infile)
{
cout<<"cannot open file";
}
I think you need to flush the screen. Once you have flushed and closed the stream. The next time you run an application it should open the file.
e.g.
inFile.flush();
inFile.close();

Problem reading and writing from same file within same program... C++

I'm working on a program, that needs to load data from a text file upon starting and save data to THE SAME text file upon exit. I have the load working, and i have the save working, but for some reason I cant seem to have them both work within the same program.
This doesnt work...
ifstream loadfile("test.txt");
ofstream savefile("test.txt");
void load()
{
string name;
while(!loadfile.eof())
{
getline(loadfile,name);
cout<<"name " << name<<"\n";
}
}
void save(User &name)
{
savefile << name.getName() << endl;
}
Neither does this...
fstream file("test.txt");
void load()
{
string name;
while(! file.eof())
{
getline(file,name);
cout<<"name " << name<<"\n";
}
}
void save(User &name)
{
file << name.getName() << endl;
}
The thing is, I can save a list of names, which works fine... but as soon as i start the program, all the names from the list delete from the text file.
Also, I know that getline() gets the data from the text file as a string type, but how would i convert that to something like an int.
Thanks
Your files are being opened globally and never closed. Try:
void load()
{
ifstream loadfile("test.txt");
string name;
while(!loadfile.eof())
{
getline(loadfile,name);
cout<<"name " << name<<"\n";
}
}
void save(User &name)
{
ofstream savefile("test.txt");
savefile << name.getName() << endl;
}
ofstream savefile("test.txt");
is equivalent to:
ofstream savefile;
savefile.open("test.txt", ios::out|ios::trunc);
That is, you're truncating the file as you open it. So, move the initialization of savefile to happen after you're done with your load call (I'd suggest doing it as late as possible, because if you crash after that initialization and before you're done saving, the save file is corrupted -- normally one writes to a different file and only does the rename at the very end when everything is safe on disk).
In your first sample, you may be running afoul of OS file locking, preventing you from opening the same file for both read and write. Remember to always check for failure when opening a file.
In the second sample, you don't rewind the file pointer. Use seekg to reset the stream pointer before trying to read. Keep in mind that although there's a seperate seekg and seekp, in practice they may refer to the same pointer, so it's always best to seek before switching between read and write.
void load(){
ifstream loadfile("test.txt");
string name;
while(!loadfile.eof())
{
getline(loadfile,name);
cout<<"name " << name<<"\n";
}
loadfile.close(); // Call close() to free up resources again
}
void save(User &name)
{
ofstream savefile("test.txt");
savefile << name.getName() << endl;
savefile.close(); // Call close() to free up resources again
}
From Cplusplus I/O:
"Once this member function is called, the stream object can be used to open another file, and the file is available again to be opened by other processes."