I have a class where I store a filename that a user has provided:
string EMNfn; // IDF file EMN name
// IDF file EMN name
void CcaAna::put_EMNfn(string s)
{
CcaAna::EMNfn = s;
}
string CcaAna::get_EMNfn()
{
return EMNfn;
}
However, when I try to open the file, and I know it exists in the current directory that I am using with the following:
femn.open(cCCA.get_EMNfn());
I get a compile error C2664 ...cannot convert parameter 1 from 'class std::basic_string,class std::allocator >' to 'const char *'
When I try using:
femn.open(cCCA.get_EMNfn().c_str());
it compiles but trips my error code:
if(!femn)
{
cout << "Open of Original EMN file failed\n";
cout << "EMN file: " << cCCA.get_EMNfn() << endl;
cout << "Press any key to exit" << endl;
ch = getchar();
return 1;
}
However when I type it in directly everthing works fine:
femn.open("262-003841-7-23.emn");
running out of ideas is there another way to open the stream?
molbdnilo - I think you are on to something (see below)
OK I added the two COUT lines after and I have included the OUTPUT below the code:
cout << "EMN file: " << cCCA.get_EMNfn() << endl;
// THIS WORKS
// femn.open("262-003841-7-23.emn");
femn.open(cCCA.get_EMNfn().c_str());
// femn.open(cCCA.get_EMNfn());
cout << "this works: " << "262-003841-7-23.emn" << endl;
cout << "*****" << cCCA.get_EMNfn() << "*****" << endl;
OUTPUT:
PROCESSING USER INPUT FILE ...
EMN file: "262-003841-7-23.emn"
this works: 262-003841-7-23.emn
*****"262-003841-7-23.emn"*****
Open of Original EMN file failed
EMN file: "262-003841-7-23.emn"
Press any key to exit
What I am seeing is that the stored string has " around it. Is there a C++ way to remove those?
You are not assigning strings correctly!string variables should not be assigned with = operator . Here is a reference for working with strings.
There are lots of ways for doing your task here is one:
#include <string.h>
...
strcpy(CcaAna::EMNfn,s);//instead of CcaAna::EMNfn=s;
maybe this might work,if not check the link and use a correct way to work with strings.
cheers
Related
I am trying to logg my events so i thought of using ostringstream to save the output and then send it to a function where i print the output on screen and on file fstream fileOut. It wont work, it just gives me random numbers and seem not to output all new outputs on the same file but just creates a new file everytime and deletes what was on it before. How do i do this?
where the print happens:
void Event::output(ostringstream* info) {
std::cout << info << std::endl;
fileOut << info << std::endl;
}
where the output happens:
ostringstream o;
if (time < SIM_TIME) {
if (status->tryAssemble(train)) {
Time ct;
ct.fromMinutes(time);
o << ct << " Train [" << train->getTrainNumber() << "] ";
Time t(0, DELAY_TIME);
o << "(ASSEMBLED) from " << train->getStart() << " " << train->getScheduledStartTime() <<
" (" << train->getStartTime() << ") to " << train->getDest() << " " << train->getScheduledDestTime() <<
" (" << train->getDestTime() << ") delay (" << train->getDelay() << ") speed=" << train->getScheduledSpeed() <<
" km/h is now assembled, arriving at the plateform at " << train->getStartTime() - t << endl << endl;
fileOut.open("testfile.txt", std::ios::out);
if (!fileOut.is_open())
exit(1); //could not open file
output(&o);
train->setStatus(ASSEMBLED);
time += ASSEMBLE_TIME;
Event *event = new ReadyEvent(simulation, status, time, train);
simulation->addEvent(event);
It wont work, it just gives me random numbers
You are passing the ostringstream to your function by pointer. There is no operator<< that takes an ostringstream* pointer as input and prints its string content. But there is an operator<< that takes a void* as input and prints the memory address that the pointer is pointing at. That is the "random numbers" you are seeing. ANY type of pointer can be assigned to a void* pointer.
You need to dereference the ostringstream* pointer to access the actual ostringstream object. Even so, there is still no operator<< that takes an ostringstream as input. However, ostringstream has a str() method that returns a std::string, and there is an operator<< for printing a std::string:
void Event::output(ostringstream* info) {
std::string s = info->str();
std::cout << s << std::endl;
fileOut << s << std::endl;
}
That being said, you should pass the ostringstream by const reference instead of by pointer, since the function does not allow a null ostringstream to be passed in, and it does not modify the ostringstream in any way:
void Event::output(const ostringstream &info) {
std::string s = info.str();
std::cout << s << std::endl;
fileOut << s << std::endl;
}
...
output(o);
seem not to output all new outputs on the same file but just creates a new file everytime and deletes what was on it before.
That is because you are not opening the file with either the app or ate flag 1, so it creates a new file each time, discarding the contents of any existing file. If you want to append to an existing file instead, you need to either:
use the ate flag to "seek to the end of stream immediately after open":
fileOut.open("testfile.txt", std::ios::out | std::ios::ate);
use the app flag to "seek to the end of stream before each write":
fileOut.open("testfile.txt", std::ios::out | std::ios::app);
1: if fileOut is a std::ofstream, you do not need to specify std::ios::out explicitly.
I want to add new string at the end of file when I register new user its overwrite the previous values.
write.open("usersinfo.txt");
if (write.is_open())
{
write << username << "\t" << password << "\t" << cnpassword << "\t" << email << "\t" << number << "\n\n";
cout << "\n\n\nPlease Wait Your Data Is Saving";
for(int i=0;i<10;i++)
{
cout << ".";
Sleep(400);
}
cout << "\n\n\t\t\tSign Up Successfull";
write.close();
}
Use
write.open("usersinfo.txt", std::ios::app);
to open the file with the write pointer already at the end (i.e., if you want to append to the file).
EDIT: Upon double-checking the standard, the first edit turned out to be unnecessary. std::ios::app implies std::ios::out (27.9.1.4).
you should open your file in append mode so you can add your new text after what you have writen before.
The right way is
write.open("usersinfo.txt", std::ios::app);
instead
write.open("usersinfo.txt"); is equal to
write.open("usersinfo.txt", std::ios::out);
I'm trying to learn about the fstream class and I'm having some trouble. I created a couple of txt files, one with a joke and the other with a punchline (joke.txt) and (punchline.txt) just for the sake of reading in and displaying content. I ask the user for the file name and if found it should open it up, clear the flags then read the content in. but I cant even test what it reads in because I'm currently getting errors regarding a deleted function but I don't know what that means
error 1:
"IntelliSense: function "std::basic_ifstream<_Elem, _Traits>::basic_ifstream(const std::basic_ifstream<_Elem, _Traits>::_Myt &) [with _Elem=char, _Traits=std::char_traits<char>]" (declared at line 818 of "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\fstream") cannot be referenced -- it is a deleted function
the second error is the exact same but for the 2nd function (displayLastLine())
and error 3:
Error 1 error C2280: 'std::basic_ifstream<char,std::char_traits<char>>::basic_ifstream(const std::basic_ifstream<char,std::char_traits<char>> &)' : attempting to reference a deleted function
and here's my code:
#include "stdafx.h"
#include <string>
#include <iostream>
#include <fstream>
using namespace std;
void displayAllLines(ifstream joke);
void displayLastLine(ifstream punchline);
int main()
{
string fileName1, fileName2;
ifstream jokeFile, punchlineFile;
// Desribe the assigned project to the User
cout << "This program will print a joke and its punch line.\n\n";
cout << "Enter the name of the joke file (ex. joke.txt): ";
cin >> fileName1;
jokeFile.open(fileName1.data());
if (!jokeFile)
{
cout << " The file " << fileName1 << " could not be opened." << endl;
}
else
{
cout << "Enter name of punch line file (ex. punchline.txt): ";
cin >> fileName2;
punchlineFile.open(fileName2.data());
if (!punchlineFile)
{
cout << " The file " << fileName2 << " could not be opened." << endl;
jokeFile.close();
}
else
{
cout << endl << endl;
displayAllLines(jokeFile);
displayLastLine(punchlineFile);
cout << endl;
jokeFile.close();
punchlineFile.close();
}
}
// This prevents the Console Window from closing during debug mode
cin.ignore(cin.rdbuf()->in_avail());
cout << "\nPress only the 'Enter' key to exit program: ";
cin.get();
return 0;
}
void displayAllLines(ifstream joke)
{
joke.clear();
joke.seekg(0L, ios::beg);
string jokeString;
getline(joke, jokeString);
while (!joke.fail())
{
cout << jokeString << endl;
}
}
void displayLastLine(ifstream punchline)
{
punchline.clear();
punchline.seekg(0L, ios::end);
string punchString;
getline(punchline, punchString);
while (!punchline.fail())
{
cout << punchString << endl;
}
}
You do call a deleted function, being the copy constructor of the class std::ifstream.
If you take a look at the reference you notice, that the copy constructor is not allowed.
so instead of using:
void displayAllLines(ifstream joke);
void displayLastLine(ifstream punchline);
you should work with calls by reference:
void displayAllLines(ifstream& joke);
void displayLastLine(ifstream& punchline);
Using a reference will behave just like calling the method with a copy, but in fact you are operating on the original object instead of a new copy-constructed object. Keep that in mind for further use of the call by reference.
I thought I understood having to cast a std::string as a *char when opening a file, but I am missing something. It compiles fine but does not open. Tried a number of variations but so far only hardcoding the name in the file is working:
// const char * cEMN = cCCA.get_EMNfn().c_str();
// femn.open(cEMN); fails
// femn.open("file-foo.emn"); works
string stdEMN;
stdEMN = cCCA.get_EMNfn();
femn.open(stdEMN.c_str()); // fails
if(!femn)
{
cout << "Open of Original EMN file failed\n";
cout << "EMN file: " << cCCA.get_EMNfn() << endl;
cout << "Press any key to exit" << endl;
ch = getchar();
return 1;
}
The facts as I discern them to be are that:
femn.open("file-foo.emn");
succeeds. But
femn.open(stdEMN.c_str());
fails.
The obvious conclusion is that stdEMN.c_str() evaluates to a string that differs from "file-foo.emn".
Im working on my homework assignment and I stuck because in the assignment we have to ask the user to enter a file name but also to type in either wc cc or lc (word count, character count, and line count of a file. For example, wc filename.txt. Im suppose to check the file to see if its valid or not which i understand and I know how to compare the users input to determine the different kind of function to run, but I dont understand how you could do it together. Any ideas? This is what I have so far.
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main()
{
string line;
string file;
ifstream input; //input file stream
int i;
cout << "Enter a file name" << endl;
while(true){
cout << ">" ;
getline(cin,file);
input.open(file.c_str());
if (input.fail()) {
cerr << "ERROR: Failed to open file " << file << endl;
input.clear();
}
else {
i = 0;
while (getline(input, line))
if(line == "wc"){
cout << "The word count is: " << endl;
}
else if(line == "cc"){
cout << "The character count is: " << endl;
}
else if(line == "lc"){
cout << "The line count is: " << endl;
}
else if(line == "exit"){
return 0;
}
else{
cout << "----NOTE----" << endl;
cout << "Available Commands: " << endl;
cout <<"lc \"filename\"" << endl;
cout <<"cc \"filename\"" << endl;
cout <<"wc \"filename\"" << endl;
cout <<"exit" << endl;
}
}
}
return 0;
}
void wordCount(){
//TBD
}
void characterCount(){
//TBD
}
void lineCount(){
//TBD
}
You have to find the space between the command and the file name in the users input and then split the string where you find the space. Something like this
cout << "Enter a command\n";
string line;
getline(cin, line);
// get the position of the space as an index
size_t space_pos = line.find(' ');
if (space_pos == string::npos)
{
// user didn't enter a space, so error message and exit
cout << "illegal command\n";
exit(1);
}
// split the string at the first space
string cmd = line.substr(0, space_pos);
string file_name = line.substr(space_pos + 1);
This is untested code.
You could do better than this, for instance this would not work if the user entered two spaces between the command and the file name. But this kind of work rapidly gets very tedious. As this is an assignment I would be tempted to move on to more interesting things. You can always come back and improve things later if you have the time.
I think you are asking how to validate multiple arguments: the command and the file.
A simple strategy is to have function like the following:
#include <fstream> // Note: this is for ifstream below
bool argumentsInvalid(const string& command, const string & command) {
// Validate the command
// Note: Not ideal, just being short for demo
if("wc" != command && "cc" != command && "lc" != command) {
std::cout << "Invalid command" << std::endl;
return false;
}
// Validate the file
// Note: This is a cheat that uses the fact that if its valid, its open.
std::ifstream fileToRead(filename);
if(!fileToRead) {
std::cout << "Invalid file: \"" << filename << "\"" << std::endl;
return false;
}
return true;
// Note: This does rely on the ifstream destructor closing the file and would mean
// opening the file twice. Simple to show here, but not ideal real code.
}
If you want to evaluate ALL arguments before returning an error, insert a flag at the top of that function, like:
// To be set true if there is an error
bool errorFound = false;
and change all of the returns in the conditions to:
errorFound = true;
and the final return to:
return !errorFound;
Usage:
....
if(argumentsInvalid(command, filename)) {
std::cout << "Could not perform command. Skipping..." << std::endl;
// exit or continue or whatever
}
// Now do your work
Note: The specific validity tests here are over simplified.