Reuse a filestream in C++? - c++

I have a program that takes multiple files as input. What I'm trying to do is use the same filestream? I keep getting an error when trying to open the stream with the second file. Why is not code not valid and creating an error at compile time? argv[2] is a const char*.
error: no match for call to '(std::ifstream) (char*&)'
ifstream fin(argv[1]);
//work with filestream
fin.close();
fin(argv[2]);
//work with filestream
fin.close();

The first line ifstream fin(argv[1]); is evoking ifstream's constructor, and the constructor can only be called once per object. Your code is trying to call it a second time. Try using open() instead:
fin.open(argv[2]);
As an aside, you may also want to call clear() before you reopen your ifstream. The reason for this is that if the first open() (or even close()) fails, error bits on the ifstream will be set, and won't be cleared by close().

Use a local scope:
{
ifstream fin(argv[1]);
//work with filestream
}
{
ifstream fin(argv[2]);
//work with filestream
}
Note that you dont manually need to close the streams, this is handled automatically when they go out of scope.

Related

In c++, is stream.clear() necessary after a failure has occurred?

I have the following code:
string promptPlayerForFile(ifstream &infile, string prompt) {
while (true) {
string filename;
cout << prompt;
getline(cin, filename);
infile.open(filename.c_str());
if (!infile.fail()) return filename;
infile.clear();
cout << "Unable to open that file. Try again." << endl;
}
}
The function works as expected: you enter file names until you give a correct one, in which case it associates a stream with the file and returns the filename string.
I then tried commenting out the line infile.clear() to see what happens. (I read that it needs to be included after a failure has occurred in order to reset the relevant bits of the stream.)
However, after commenting this out, the function behaves as before. If I first give a wrong filename and then a correct one it works, so somehow the failure bits get reset even without that line. Is then infile.clear() necessary and what are its appropriate uses?
If you are using C++11 or higher, you don't need to call infile.clear();. If open() is successful, then clear() is called.
If you are using a pre-C++11 compiler, it is necessary to call infile.clear(). The language does not guarantee that the failbit(s) are cleared when open() is successful.
See https://en.cppreference.com/w/cpp/io/basic_ifstream/open for details about the call to clear().
the infile.clear() is relevant if and only if you want to continue to interact with the stream (e.g. read from it). If your program ends anyway, you dont't have to clear the error flags.

What happens if I never call `close` on an open file stream? [duplicate]

This question already has answers here:
do I need to close a std::fstream? [duplicate]
(3 answers)
Closed 7 years ago.
Below is the code for same case.
#include <iostream>
#include <fstream>
using namespace std;
int main () {
ofstream myfile;
myfile.open ("example.txt");
myfile << "Writing this to a file.\n";
//myfile.close();
return 0;
}
What will be the difference if I uncomment the myfile.close() line?
There is no difference. The file stream's destructor will close the file.
You can also rely on the constructor to open the file instead of calling open(). Your code can be reduced to this:
#include <fstream>
int main()
{
std::ofstream myfile("example.txt");
myfile << "Writing this to a file.\n";
}
To fortify juanchopanza's answer with some reference from the std::fstream documentation
(destructor)
[virtual](implicitly declared)
destructs the basic_fstream and the associated buffer, closes the file
(virtual public member function)
In this case, nothing will happen and code execution time is very less.
However, if your codes runs for long time when you are continuously opening files and not closing, after a certain time, there may be crash in run time.
when you open a file, the operating system creates an entry to represent that file and store the information about that opened file. So if there are 100 files opened in your OS then there will be 100 entries in OS (somewhere in kernel). These entries are represented by integers like (...100, 101, 102....). This entry number is the file descriptor. So it is just an integer number that uniquely represents an opened file in operating system. If your process open 10 files then your Process table will have 10 entries for file descriptors.
Also, this is why you can run out of file descriptors, if you open lots of files at once. Which will prevent *nix systems from running, since they open descriptors to stuff in /proc all the time.
Similar thing should happen in case of all operating system.
Under normal conditions there is no difference.
BUT under exceptional conditions (with slight change) the call to close can cause an expception.
int main()
{
try
{
ofstream myfile;
myfile.exceptions(std::ios::failbit | std::ios::badbit);
myfile.open("example.txt");
myfile << "Writing this to a file.\n";
// If you call close this could potentially cause an exception
myfile.close();
// On the other hand. If you let the destructor call the close()
// method. Then the destructor will catch and discard (eat) the
// exception.
}
catch(...)
{
// If you call close(). There is a potential to get here.
// If you let the destructor call close then the there is
// no chance of getting here.
}
}

Implementing File class for both read and write operations on the file

I need to implement a class which holds a regular text file that will be valid for both read and write operations from multiple threads (say, "reader" threads and "writers").
I am working on visual studio 2010 and can use only the available libraries that it (VS 2010) has, so I chose to use the std::fstream class for the file operations and the CreateThread function & CRITICAL_SECTION object from the header.
I might start by saying that I seek, at the beginning, for a simple solution - just so it works....:)
My idea is as follows:
I created a File class that will hold the file and a "mutex" (CRITICAL_SECTION object) as private members.
In addition, this class (File class) provides a "public interface" to the "reader/writer" threads in order to perform a synchronized access to the file for both read and write operations.
See the header file of File class:
class File {
private:
std::fstream iofile;
int size;
CRITICAL_SECTION critical;
public:
File(std::string fileName = " ");
~File();
int getSize();
// the public interface:
void read();
void write(std::string str);
};
Also see the source file:
#include "File.h"
File :: File(std::string fileName)
{
// create & open file for read write and append
// and write the first line of the file
iofile.open(fileName, std::fstream::in | std::fstream::out | std::fstream::app); // **1)**
if(!iofile.is_open()) {
std::cout << "fileName: " << fileName << " failed to open! " << std::endl;
}
// initialize class member variables
this->size = 0;
InitializeCriticalSection(&critical);
}
File :: ~File()
{
DeleteCriticalSection(&critical);
iofile.close(); // **2)**
}
void File :: read()
{
// lock "mutex" and move the file pointer to beginning of file
EnterCriticalSection(&critical);
iofile.seekg(0, std::ios::beg);
// read it line by line
while (iofile)
{
std::string str;
getline(iofile, str);
std::cout << str << std::endl;
}
// unlock mutex
LeaveCriticalSection(&critical);
// move the file pointer back to the beginning of file
iofile.seekg(0, std::ios::beg); // **3)**
}
void File :: write(std::string str)
{
// lock "mutex"
EnterCriticalSection(&critical);
// move the file pointer to the end of file
// and write the string str into the end of the file
iofile.seekg(0, std::ios::end); // **4)**
iofile << str;
// unlock mutex
LeaveCriticalSection(&critical);
}
So my questions are (see the numbers regarding the questions within the code):
1) Do I need to specify anything else for the read and write operations I wish to perform ?
2) Anything else I need to add in the destrutor?
3) What do I need to add here in order that EVERY read operation will occur necessarily from the beginning of the file ?
4) What do I need to modify/add here in order that each write will take place at the end of the file (meaning I wish to append the str string into the end of the file)?
5) Any further comments will be great: another way to implement , pros & cons regarding my implementation, points to watch out , etc'.....
Thanks allot in advance,
Guy.
You must handle exceptions (and errors in general).
No, you destructor even has superfluous things like closing the underlying fstream, which the object takes care of itself in its destructor.
If you always want to start reading at the beginning of the file, just open it for reading and you automatically are at the beginning. Otherwise, you could seek to the beginning and start reading from there.
You already opened the file with ios::app, which causes every write operation to append to the end (including that it ignores seek operations that set the write position, IIRC).
There is a bunch that isn't going to work like you want it to...
Most importantly, you need to define what you need the class to behave like, i.e. what the public interface is. This includes guarantees about the content of the file on disk. For example, after creating an object without passing a filename, what should it write to? Should that really be a file who's name is a single space? Further, what if a thread wants to write two buffers that each contain 100 chars? The only chance to not get interrupted is to first create a buffer combining the data, otherwise it could get interrupted by a different thread. It gets even more complicate concerning the guarantees that your class should fulfill while reading.
Why are you not using references when passing strings? Your tutorial should mention them.
You are invoking the code to enter and leave the critical section at the beginning and end of a function scope. This operation should be bound to the ctor and dtor of a class, check out the RAII idiom in C++.
When you are using a mutex, you should document what it is supposed to protect. In this case, I guess it's the iofile, right? You are accessing it outside the mutex-protected boundaries though...
What is getSize() supposed to do? What would a negative size indicate? In case you want to signal errors with that, that's what exceptions are for! Also, after opening an existing, possibly non-empty file, the size is zero, which sounds weird to me.
read() doesn't return any data, what is it supposed to do?
Using a while-loop to read something always has to have the form "while try-to-read { use data}", yours has the form "while success { try-to-read; use data; }", i.e. it will use data after failing to read it.
Streams have a state, and that state is sticky. Once the failbit is set, it remains set until you explicitly call clear().
BTW: This looks like logging code or a file-backed message queue. Both can be created in a thread-friendly way, but in order to make suggestions, you would have to tell us what you are actually trying to do. This is also what you should put into a comment section on top of your class, so that any reader can understand the intention (and, more important now, so that YOU make up you mind what it's supposed to be).

Why doesn't closing a file automatically clear error state?

When I use ifstream to read file, I loop over all lines in the file and close it. Then I try opening a different file with the same ifstream object, it still says the End-Of-File error. I'm wondering why closing the file won't automatically clearing the state for me. I have to call clear() explictly after close() then.
Is there any reason why they design it like this? To me, that's really painful if you wanna reuse the fstream object for different files.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
void main()
{
ifstream input;
input.open("c:\\input.txt");
string line;
while (!input.eof())
{
getline(input, line);
cout<<line<<endl;
}
// OK, 1 is return here which means End-Of-File
cout<<input.rdstate()<<endl;
// Why this doesn't clear any error/state of the current file, i.e., EOF here?
input.close();
// Now I want to open a new file
input.open("c:\\output.txt");
// But I still get EOF error
cout<<input.rdstate()<<endl;
while (!input.eof())
{
getline(input, line);
cout<<line<<endl;
}
}
Personally, I think close() should reset the flags, as I've been bitten by this in the past. Still, to mount my hobby-horse once more, your read code is wrong:
while (!input.eof())
{
getline(input, line);
cout<<line<<endl;
}
should be:
while (getline(input, line))
{
cout<<line<<endl;
}
To see why, consider what happens if you try to read a completely empty file. The eof() call will return false (because although the file is empty, you have not yet read anything, and only reads set the eof bit) and you will output a line which does not exist.
The call to close may fail. When it does fail, it sets the failbit. If it reset the state of the stream, you wouldn't be able to check whether or not the call to close succeeded.
Because the flags are associated with the stream, not the file.
This has been changed in C++11 (C++0x), not so that close() discards any errors detected but the next open() will call clear() for you.

Do I need to manually close an ifstream?

Do I need to manually call close() when I use a std::ifstream?
For example, in the code:
std::string readContentsOfFile(std::string fileName) {
std::ifstream file(fileName.c_str());
if (file.good()) {
std::stringstream buffer;
buffer << file.rdbuf();
file.close();
return buffer.str();
}
throw std::runtime_exception("file not found");
}
Do I need to call file.close() manually? Shouldn't ifstream make use of RAII for closing files?
NO
This is what RAII is for, let the destructor do its job. There is no harm in closing it manually, but it's not the C++ way, it's programming in C with classes.
If you want to close the file before the end of a function you can always use a nested scope.
In the standard (27.8.1.5 Class template basic_ifstream), ifstream is to be implemented with a basic_filebuf member holding the actual file handle. It is held as a member so that when an ifstream object destructs, it also calls the destructor on basic_filebuf. And from the standard (27.8.1.2), that destructor closes the file:
virtual ˜basic_filebuf();
Effects: Destroys an object of class basic_filebuf<charT,traits>. Calls close().
Do you need to close the file?
NO
Should you close the file?
Depends.
Do you care about the possible error conditions that could occur if the file fails to close correctly? Remember that close calls setstate(failbit) if it fails. The destructor will call close() for you automatically because of RAII but will not leave you a way of testing the fail bit as the object no longer exists.
You can allow the destructor to do it's job. But just like any RAII object there may be times that calling close manually can make a difference. For example:
#include <fstream>
using std::ofstream;
int main() {
ofstream ofs("hello.txt");
ofs << "Hello world\n";
return 0;
}
writes file contents. But:
#include <stdlib.h>
#include <fstream>
using std::ofstream;
int main() {
ofstream ofs("hello.txt");
ofs << "Hello world\n";
exit(0);
}
doesn't. These are rare cases where a process suddenly exits. A crashing process could do similar.
No, this is done automatically by the ifstream destructor. The only reason you should call it manually, is because the fstream instance has a big scope, for example if it is a member variable of a long living class instance.