I am learning filestreams. I have a problem while using ifstream in a separate function outside main. Inside main it works just fine. the function is such,
void counter(string str)
{
ifstream inpufile(str,ios::in);//the error is here, it says the function cannot be called!?!
if(!inpufile)
{
cout<<"\n The file does not exist, try again";
}
else
{
char c;
int counter=0;
while(inpufile.get(c))
{
if(c=='\n')
counter++;
}
cout<<"\n The number of lines in the file are "<<counter+1;
}
inpufile.close();
}
The function call is from main() and is such
counter(argv[1]);
Can I only pass ifstream as an object. Can I not create one outside main?
Your problem doesn't have anything to do with the function, it has to do with the variable holding the filename. Consider:
int main(int argc, const char** argv)
{
std::ifstream inpufile(argv[1], ios::in); // ok
std::string fname = argv[1]; // ok
std::ifstream fileb(str, ios::in); // fails pre-C++11
}
By having a function, you're causing an implicit conversion from const char* to std::string, just like in the example above. And std::fstream didn't take std::string for the filename until C++11. Two ways to fix:
void counter(const char* fname)
{
ifstream inpufile(fname, ios::in); // works now
and counter(argv[1]); still works, in fact it works a tiny bit better because no conversion is needed.
Or
void counter(std::string fname)
{
ifstream inpufile(str.c_str(), ios::in); // ok too
Which gets the const char* that fstream expects.
C++11 does finally fix this and let you use std::string directly.
Yes you can create it inside a function. The function is correct.
In case (before C++11) you need to turn std::string to char*, you can use c_str().
So change this:
ifstream inpufile(str,ios::in);
to this:
ifstream inpufile(str.c_str(),ios::in);
You could do it like this:
void counter(string str, ifstream& inpufile) {
if (!inpufile) {
cout << "\n The file does not exist, try again";
} else {
char c;
int counter = 0;
while (inpufile.get(c)) {
if (c == '\n')
counter++;
}
cout << "\n The number of lines in the file are " << counter + 1;
}
inpufile.close();
}
int main() {
string str = "Team.txt";
ifstream inpufile(str.c_str(), ios::in);
counter(str, inpufile);
return 0;
}
You could also create the file object in main and open it inside the function like this:
void counter(string str, ifstream& inpufile) {
inpufile.open(str.c_str(), ios::in);
if (!inpufile) {
cout << "\n The file does not exist, try again";
} else {
char c;
int counter = 0;
while (inpufile.get(c)) {
if (c == '\n')
counter++;
}
cout << "\n The number of lines in the file are " << counter + 1;
}
inpufile.close();
}
int main() {
string str = "Team.txt";
ifstream inpufile;
counter(str, inpufile);
return 0;
}
Your code feeds the function with the filename and then creates the file object inside the function.
ifstream inpufile(str.c_str());
ios::in isn't necessary as it's implicitly set.
Related
#include<iostream>
#include<fstream>
using namespace std;
void read_file(fstream &file);
int main()
{
fstream inFile;
inFile.open("Data.txt");
if (inFile.fail())
{
cerr << "Error with opening file";
exit(1);
}
else
{
read_file(inFile);
}
inFile.close();
return 0;
}
void read_file(fstream &file)
{
int arr[100];
fstream inFile;
int number;
int number_trash;
int number_hold;
while (!inFile.eof())
{
for (int i = 0; i < 101; i++)
{
inFile >> number;
number_hold = number;
if (number != number_hold)
{
arr[i] = number;
cout << arr[i] << endl;
}
else
{
number_trash = number;
}
}
}
}
In your read_file() function, you're passing an fstream instance of an already open file, which is correct, however, later in the same function, you declare a new instance of fstream called inFile which is not open and you're trying to read from this file stream.
Remove the fstream inFile and read from the file which your function takes as an argument.
Also, your algorithm is not correct - the first if statement condition will be always evaluated to false. You're assigning number to number_hold and then you're checking for their non-equality.
As a solution, consider something like this:
void read_file(fstream &file)
{
set<int> arr; // storage for your unique numbers
while (!file.eof())
{
int number;
file >> number; // read the number
// check if this number is already in your unique list
if (arr.find(number) == arr.end()) { // If it isn't, print it out...
cout << number << endl;
arr.insert(number); // ...and put it to your unique list
}
}
}
Note that for this to work you have to include another header file called set
#include <set>
//it is a function to take file name and create it.
void createfile(string filename)
{
ofstream file;
file.open(filename,ios::out);
if(file.fail())
{
cout<<"file is failed"<<endl;
}
else
{
cout<<"file is opened"<<endl;
}
}
//it is a function which takes name of file and display it's content.
void displaycontent(string name)
{
ifstream file;
file.open(name);
string y;
while(!file.eof())
{
getline(file,y);
cout<<y<<endl;
}
}
How can I display the content of the file that I already created in the first function?
int main()
{
string filename;
cin>>filename;
createfile(filename);
displaycontent(filename);
return 0;
}
The program never writes anything to the file, so there is no content to display. Also, the loop is faulty. If an error occurs reading the file, file.eof() will never be true, the following will loop forever.
void displaycontent(string name)
{
ifstream file;
file.open(name);
string y;
while(!file.eof()) // WRONG
{
getline(file,y);
cout<<y<<endl;
}
}
Instead, you want this (omitting error-handling):
void display_file(const string &file_name) // Note pass by reference
{
std::ifstream file;
file.open(file_name);
std::string y;
while(std::getline(file,y)) {
std::cout << y << '\n';
}
}
Or better yet,
void display_file(const string &file_name)
{
std::ifstream file(file_name);
std::cout << file.rdbuf();
}
call the create function inside the display function (in else's scope )...
as the create function is passed by value so any changes that will happen to what's inside of it will stay within the scope
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
void read();
int main() {
read();
return 0;
}
void read () {
string file("");
string nameOfFile("");
cin >> nameOfFile;
ifstream in (nameOfFile);
while ( !in.eof() ) {
getline(in, file);
cout << file;
cout << endl;
}
cout << file;
in.close();
}
How come this isn't working, I'm trying to make it so i can type in which file i want to read?
I'm really new to C++, sorry if this is an obvious fix.
You have to change
ifstream in (nameOfFile);
with
ifstream in (nameOfFile.c_str());
because the default constructor for ifstream does not accept a std::string as an argument, it needs a char *. Hence, use the function std::string::c_str() to convert a std::string into a char *.
A little feedback:
void read () {
string file(""); // you don't need the ("") bit; empty by default,
// and "file" is a terrible choice of identifier as
// it sounds more like an ifstream than a string
// used to hold one line from the file.
// I tend to use "string line;" for this.
string nameOfFile(""); // ditto
cin >> nameOfFile; // you should test for success of input, like this:
// if (!cin >> nameOfFile) {
// std::cerr << "error reading filename from stdin\n";
// exit(1);
// }
ifstream in (nameOfFile); // test for success getting file open like this:
// if (ifstream in(nameofFile))
// {
while ( !in.eof() ) { // NEVER check eof before attempting input, instead:
getline(in, file); // while (getline(in, file))
cout << file; // cout << file << endl; // can "chain"
cout << endl; // }
// else
// std::cerr << "couldn't open " << nameOfFile
// << '\n';
} // no need for extra cout nor explicit close, as
cout << file; // the ifstream destructor closes anyway.
in.close();
}
You need to open the ifstream usign in.open(), and hendle the case where file does not exist as well. here is the function:
void read() {
string file("");
string fileContent = "";
string nameOfFile("");
cin >> nameOfFile;
ifstream in(nameOfFile.c_str());
in.open(nameOfFile, ios::in);
if (in){
while (!in.eof()) {
getline(in, file);
fileContent += file;
}
cout << fileContent;
in.close();
}
else {
cout << "Could not open file.";
}
}
I have posted the following code where I am reading from an input file -- storing information in a structure -- and then writing to an output file. I know that the eof function is not safe and hence one must use the getline function to check whether the end of file has been detected or not; however, in this particular code, I have not been able to use the getline function and hence has finally relied on the eof function. Hence, can you please suggest an alternative to the eof function or let me know how I can use the getline function when I am trying to initialize an array of structures . I have used two asterisk symbols to indicate where I want to use the getline function.
#include <iostream>
#include <fstream>
using namespace std;
//student structure
struct student
{
char name[30];
char course[15];
int age;
float GPA;
};
ifstream inFile;
ofstream outFile;
student getData();
void writeData(student writeStudent);
void openFile();
int main (void)
{
const int noOfStudents = 3; // Total no of students
openFile(); // opening input and output files
student students[noOfStudents]; // array of students
// Reading the data from the file and populating the array
for(int i = 0; i < noOfStudents; i++)
{
if (!inFile.eof()) // ** This where I am trying to use a getline function.
students[i] = getData();
else
break ;
}
for(int i = 0; i < noOfStudents; i++)
writeData(students[i]);
// Closing the input and output files
inFile.close ( ) ;
outFile.close ( ) ;
}
void openFile()
{
inFile.open("input.txt", ios::in);
inFile.seekg(0L, ios::beg);
outFile.open("output.txt", ios::out | ios::app);
outFile.seekp(0L, ios::end);
if(!inFile || !outFile)
{
cout << "Error in opening the file" << endl;
exit(1);
}
}
student getData()
{
student tempStudent;
// temp variables for reading the data from file
char tempAge[2];
char tempGPA[5];
// Reading a line from the file and assigning to the variables
inFile.getline(tempStudent.name, '\n');
inFile.getline(tempStudent.course, '\n');
inFile.getline(tempAge, '\n');
tempStudent.age = atoi(tempAge);
inFile.getline(tempGPA, '\n');
tempStudent.GPA = atof(tempGPA);
// Returning the tempStudent structure
return tempStudent;
}
void writeData(student writeStudent)
{
outFile << writeStudent.name << endl;
outFile << writeStudent.course << endl;
outFile << writeStudent.age << endl;
outFile << writeStudent.GPA << endl;
}
You want to write an operator>> for your student type. Something like:
std::istream& operator>>(std::istream& in, student& s) {
in >> s.age; // etc.
return in;
}
Which then allows you to write:
int studentNo = 0;
students[maxStudents];
while (studentNo < maxStudents && (in >> students[studentNo]))
++studentNo;
Why not write this way?
instead of
inFile.getline(tempStudent.name, '\n');
inFile.getline(tempStudent.course, '\n');
inFile.getline(tempAge, '\n');
You may
while(inFile.getline(tempStudent.name, '\n'))
{
inFile.getline(tempStudent.course, '\n');
inFile.getline(tempAge, '\n');
//do stuffs
}
I've read a lot of tutorials and can not really find anything comprehensive on this subject.
I had written the following code to do one function:
#include <fstream>
#include <string>
#include <iostream>
using namespace std;
ifstream ReadFile( ifstream& openInputFile, string& sLine, int& chgLine );
int main()
{
int chgLine;
string MyFile, sLine,
sFile = "test.txt";
cout << "Enter a file: ";
cin >> MyFile ;
ifstream openInputFile;
if ( MyFile != sFile ) // file must be 'hello.cpp' to proceed
{
cout << "Error";
exit(0);
}
// if correct file is entered print the contents of it
ReadFile( openInputFile, sLine, chgLine );
system("pause");
return 0;
}
ifstream ReadFile( ifstream& openInputFile, string& sLine, int& chgLine )
{
while ( getline ( openInputFile, sLine ) )
{
if ( sLine.length() == 0 ) continue; // to proceed
for ( chgLine = 0; chgLine < sLine.length(); chgLine++ )
{
if ( sLine[chgLine] >= 97 && sLine[chgLine] <= 122 || sLine[chgLine] >= 65 && sLine[chgLine] <= 90 )
{
cout << sLine[chgLine];
}
}
}
}
But now I've decided to break all of this up into three functions that do what I want separately, and then call them from the main() function.
The first function opens the file:
#include <iostream>
#include <fstream>
using namespace std;
ifstream openInputFile()
{
// use a pointer..return a pointer
// ifstream definition is the challenge
ifstream *fp;
//fp = new ifstream openInputFile;
return openInputFile;
}
int main()
{
cout << "Hello, world!" << endl;
system("pause");
return 0;
}
I get stuck trying to return a pointer. I don't understand what I'm doing wrong. How can I get the last bit of code to work? And how does one return a pointer with ifstream if it has the function's type?
The C++ way to do this would be to create a class that wraps up all of the opening, reading and writing. Note that this would also handle closing the file automatically, a good example of RAII.
// FancyFile.h:
class FancyFile
{
private:
std::ifstream stream;
public:
void DoMagic();
InputFile(const std::string FilePath)
{ stream.open(FilePath.c_str()); }
~InputFile(void)
{ stream.close(); }
};
// FancyFile.cpp:
#include <fstream>
#include <string>
#include "FancyFile.h"
void FancyFile::DoMagic()
{
//.. your custom file handling code goes here
}
// main:
#include "FancyFile.h"
int main()
{
FancyFile myFancyFile("test.txt");
myFancyFile.DoMagic();
system("pause");
return 0;
}
It seems you shouldn't need to return by pointer in the above case.
If you do need to return a modified result, you may want to look into return value optimization(RVO). With RVO, you save yourself copying of temporaries (and in your case dynamic allocation) by passing in the output parameter by reference.
For example
void openInputFile(ifstream& file)
{
file.open(...);
}
int main()
{
ifstream file;
openInputFile(file);
// Work with file, since file is
// on the stack you don't have to worry about cleanup/etc
}
This gets rid of a lot of the problems dealing with dynamic allocation and may avoid the problems you are coming across. You seem to be kind-of onto this, so I'm puzzled as to the need to return the ifstream.
If you need do need to return by pointer, in that case in seems all your missing is an asterisk. For example this function:
ifstream* Blah();
should work.
The example doesn't actually show you opening the ifstream with the file name specified?
The example is requesting user input of the file name, and then saying it can only be one value?
As Doug T. said, it would probably be nicer from the example code to make use of scope to manage the ifstream.
Anyway, here is an example returning a pointer
ifstream * openInputFile( ) {
string MyFil;
string sFile = "test.txt";
cout << "Enter a file: ";
cin >> MyFile ;
if ( MyFile == sFile )
{
ifstream * inputFile = new ifstream( MyFile.c_str() );
// do some other stuff here?
return inputFile;
} else {
return null;
}
}
Then main can be
int main()
{
int chgLine;
string sLine;
ifstream *inputFile = openInputFile();
if( NULL == inputFile )
{
cout << "Error";
exit(0);
}
...