Help with the ifstream function in C++ - c++

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);
}
...

Related

C++ copying another file

i was wondering how to use c++ ifstream/ofstream to copy a file and save it as another name.
this is as far as i got. I know how to get the file, its just that i don't know how to copy that file and save it as a different name.
#include<iostream>
#include<fstream>
#include<string>
namespace std;
int main()
{
ofstream
ifstream
cout << "enter your file you want to copy"<< endl;
cin >> input_file_name;
in_file.open(input_file_name);
if (!in_file)
{
cout <<" there is no such file"<<endl;
return 0;
}
cout <<" enter the name you want to save this copy file"<<endl;
cin >> output_file_name;
out_file.open(output_file_name);
if (!out.file)
{
cout<<"file is not available"<<endl;
return 0;
}
in_file.close();
out_file.close();
return 0;
}
rdbuf with overloaded << is standard way to go.
ifstream src;
ofstream dst;
src.open("from", ios::in | ios::binary);
dst.open("toto", ios::out | ios::binary);
dst << src.rdbuf();
src.close();
dst.close();
Copy a file and save it on another file:
#include <fstream>
#include <iostream>
#include <string>
int main(int arc, char* argv[]) {
std::ifstream file1(argv[1]);
std::ofstream file2(argv[2]);
std::string line;
if (file1.good() && file2.good()) {
while (getline(file1, line)) {
file2 << line;
file2 << '\n';
}
}
file1.close();
file2.close();
}
Basically you want to read a character at a time and write said character to the output stream. There's a get() overload which accepts a streambuf output variable that would work. You could also use the example on cplusplus.com rdbuf documentation.
http://www.cplusplus.com/reference/fstream/ofstream/rdbuf/
This code below should give you a sense of what you want to do.
There are few things you should keep in mind, for example:
is the path of the file giving to read is valid?
or do you want to save the data from an output file if that file exists, before pushing new data?.
You could test this code by just creating a file into your desktop or any location, just change the filePath and destinationPath variables then run the code. (c++ 11)
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
vector<string> readFromFile(const char *filePath) {
vector<string> container;
ifstream obj(filePath); // automatically our file would be open
if (obj.is_open()) { // we check anyways
string line = "";
while(getline(obj, line)) {
if (!line.empty()) // prevent us to insert empty line into our vector
container.push_back(line);
}
obj.close(); // close after we finish reading to avoid corruption
}
return container;
}
bool pipingToDestination(vector<string>data, const char *filePath) {
std::filebuf fb; fb.open(filePath,std::ios::out); // open the file
ostream obj(&fb);
if (!data.empty() && fb.is_open()) { // make sure we have some data && the file file is open to write
for (string x: data) { // c++11
obj << x << endl;
}
fb.close();
return true;
}
return false;
}
int main() {
string filePath = "/Users/lamar/Desktop/testFile.txt";
vector<string> data = readFromFile(filePath.c_str());
cout << "File has passed data into container ... \n";
for(string x: data) {
cout << x << endl;
}
cout << "Creating destination file \n";
string destinationPath = "/Users/lamar/Desktop/destFile.txt";
cout << "has piped data into file " << boolalpha << pipingToDestination(data, destinationPath.c_str());
return 0;
}
This is not the only way to do this, but this code should put you on a direction

Why does std::ifstream does not update if defined globally

I'm trying to write a simple tail program in C++. I've tried the example from this solution and it works like a charm.
Then, I tried to make the ifstream as global. Now the code does not work anymore and nothing is showed if I edit the file.
Why this behaviour? I read the manual of ifstream::open and I don't see any kind of error but the code does not work:
Opens the file identified by argument filename, associating it with
the stream object, so that input/output operations are performed on
its content. Argument mode specifies the opening mode.
Here is the non-working code:
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int find_last_linefeed(ifstream &infile) {
infile.seekg(0,ios::end);
int filesize = infile.tellg();
for(int n=1;n<filesize;n++) {
infile.seekg(filesize-n-1,ios::beg);
char c;
infile.get(c);
if(c == 0x0A) return infile.tellg();
}
}
ifstream infile;
int main() {
int last_position=-1;
for(;;) {
infile.open("/Users/alberto/tmp/test");
int position = find_last_linefeed(infile);
if(position > last_position) {
infile.seekg(position,ios::beg);
string in;
infile >> in;
cout << in << endl;
}
last_position=position;
sleep(1);
}
}
Here is the working code:
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int find_last_linefeed(ifstream &infile) {
infile.seekg(0,ios::end);
int filesize = infile.tellg();
for(int n=1;n<filesize;n++) {
infile.seekg(filesize-n-1,ios::beg);
char c;
infile.get(c);
if(c == 0x0A) return infile.tellg();
}
}
int main() {
int last_position=-1;
for(;;) {
ifstream infile;
infile.open("/Users/alberto/tmp/test");
int position = find_last_linefeed(infile);
if(position > last_position) {
infile.seekg(position,ios::beg);
string in;
infile >> in;
cout << in << endl;
}
last_position=position;
sleep(1);
}
}
Since you open inside the loop, the stream will enter an error state on the second iteration, and keep failing after that.
Move
infile.open("/Users/alberto/tmp/test");
outside the loop, or define infile like this and don't use open at all:
ifstream infile("/Users/alberto/tmp/test");
The best alternative is to not use a global variable at all, as there's no reason for it here.
Also, find_last_linefeed fails to return anything if the file doesn't contain a linefeed, which is undefined.
—-
Regarding ifstream::open, from the standard (27.9.1.9):
Calls rdbuf()->open(s, mode | ios_base::in). If that function does not
return a null pointer calls clear(), otherwise calls setstate(failbit)
and basic_filebuf::open (27.9.1.4):
If is_open() != false, returns a null pointer

can't call ifstream in a separate function

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.

Reading Numbers from a File

I have a file with many numbers. The file looks like "192 158 100 0 20 200" basically like that. How can I load the files number values 1 at a time and display them on the screen in C++?
try something like this:
int val;
std::ifstream file("file");
while (file >> val)
std::cout << val;
The following program should print each number, one per line:
#include <iostream>
#include <fstream>
int main (int argc, char *argv[]) {
std::ifstream ifs(argv[1]);
int number;
while (ifs >> number) {
std::cout << number << std::endl;
}
}
#include <iostream>
#include <iterator>
#include <sstream>
#include <vector>
int main() {
std::ifstream fs("yourfile.txt");
if (!fs.is_open()) {
return -1;
}
// collect values
// std::vector<int> values;
// while (!fs.eof()) {
// int v;
// fs >> v;
// values.push_back(v);
// }
int v;
std::vector<int> values;
while (fs >> v) {
values.push_back(v);
}
fs.close();
// print it
std::copy(values.begin(), values.end(), std::ostream_iterator<int>(std::cout, " "));
return 0;
}
Please consider the following code:
ifstream myReadFile;
myReadFile.open("text.txt");
int output;
if (myReadFile.is_open())
{
while (fs >> output) {
cout<<output;
}
}
//Of course closing the file at the end.
myReadFile.close();
As well, please include the iostream and fstream inside your code when using the example above.
Note that you need to start open a filestream to read and you can try to read it char by char and detect is there any white space in between it.
Good luck.
Another way of doing it:
std::string filename = "yourfilename";
//If I remember well, in C++11 you don't need the
//conversion to C-style (char[]) string.
std::ifstream ifs( filename.c_str() );
//Can be replaced by ifs.good(). See below.
if( ifs ) {
int value;
//Read first before the loop so the value isn't processed
//without being initialized if the file is empty.
ifs >> value;
//Can be replaced by while( ifs) but it's not obvious to everyone
//that an std::istream is implicitly cast to a boolean.
while( ifs.good() ) {
std::cout << value << std::endl;
ifs >> value;
}
ifs.close();
} else {
//The file couldn't be opened.
}
The error-handling can be done in many ways through.

how to count the characters in a text file

im trying to count the characters inside a text file in c++, this is what i have so far, for some reason im getting 4. even thou i have 123456 characters in it. if i increase or decrease the characters i still get 4, please help and thanks in advance
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
const char FileName[] = "text.txt";
int main ()
{
string line;
ifstream inMyStream (FileName);
int c;
if (inMyStream.is_open())
{
while( getline (inMyStream, line)){
cout<<line<<endl;
c++;
}
}
inMyStream.close();
system("pause");
return 0;
}
You're counting the lines.
You should count the characters. change it to:
while( getline ( inMyStream, line ) )
{
cout << line << endl;
c += line.length();
}
There are probably hundreds of ways to do that.
I believe the most efficient is:
inMyStream.seekg(0,std::ios_base::end);
std::ios_base::streampos end_pos = inMyStream.tellg();
return end_pos;
First of all, you have to init a local var, this means:
int c = 0;
instead of
int c;
I think the old and easy to understand way is to use the get() function till the end char EOF
char current_char;
if (inMyStream.is_open())
{
while(inMyStream.get(current_char)){
if(current_char == EOF)
{
break;
}
c++;
}
}
Then c will be the count of the characters
this is how i would approach the problem:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main ()
{
string line;
int sum=0;
ifstream inData ;
inData.open("countletters.txt");
while(!inData.eof())
{
getline(inData,line);
int numofChars= line.length();
for (unsigned int n = 0; n<line.length();n++)
{
if (line.at(n) == ' ')
{
numofChars--;
}
}
sum=numofChars+sum;
}
cout << "Number of characters: "<< sum << endl;
return 0 ;
}
Just use good old C FILE pointers:
int fileLen(std::string fileName)
{
FILE *f = fopen(fileName.c_str(), "rb");
if (f == NULL || ferror(f))
{
if (f)
fclose(f);
return -1;
}
fseek(f, 0, SEEK_END);
int len = fell(f);
fclose(f);
return len;
}
I found out this simple method , hope this helps
while(1)
{
if(txtFile.peek() == -1)
break;
c = txtFile.get();
if(c != txtFile.eof())
noOfChars++;
}
This works for sure, it is designed to read character by character.
It could be easily put into a class and you may apply function for every char, so you may check for '\n', ' ' and so on. Just have some members in your class, where they can be saved, so you may only return 0 and use methods to get what exactly you want.
#include <iostream>
#include <fstream>
#include <string>
unsigned long int count(std::string string)
{
char c;
unsigned long int cc = 0;
std::ifstream FILE;
FILE.open(string);
if (!FILE.fail())
{
while (1)
{
FILE.get(c);
if (FILE.eof()) break;
cc++; //or apply a function to work with this char..eg: analyze(c);
}
FILE.close();
}
else
{
std::cout << "Counter: Failed to open file: " << string << std::endl;
}
return cc;
};
int main()
{
std::cout << count("C:/test/ovecky.txt") << std::endl;
for (;;);
return 0;
}
C++ provides you with a simple set of functions you can use to retrieve the size of stream segment.
In your case, we want to find the file end, which can be done by using fstream::seekg, and providing the fstream::end.
note that fstream is not implementing the end iterator overload, this is it's own end constant
When we've seeked towards the end of the file, we want to get the position of the stream pointer, using tellg (also known as the character count in our case).
But we're not done yet. We need to also set the stream pointer to its original position, otherwise we'll be reading from the end of the file. Something we don't want to do.
So lets call fstream::seekg again, but this time set the position to the begining of the file using fstream::beg
std::ifstream stream(filepath);
//Seek to end of opened file
stream.seekg(0, stream.end);
int size = stream.tellg();
//reset file pointer to the beginning of the file
stream.seekg(0, stream.beg);