Multiple use of same file streaming object - c++

I've written the following source code:
ifstream leggiFile;
leggiFile.open("Questions.txt",ios::in);
if (!leggiFile.good())
{
cerr << "\n\n\n\tErrore during file opening Questions.txt\n\n\n" << endl;
}
else
{
// ...
};
leggiFile.close();
system("pause");
Now I'd like to use the same object for working with a second file.
leggiFile.open("Answers.txt",ios::in);
i=0;
if(!leggiFile.good())
{
cerr << "\n\n\n\tError during opening of file answers.txt\n\n\n" << endl;
}
else
{
// ...
}
Problem: The 2nd time the file cannot be opened and the error message appears. Why?
Could you please suggest me a solution?

It's possible that you've done work on the stream that set one or more of the error flags, such as eofbit.
Closing the stream doesn't clear its error flags, you have to do it manually. Call leggiFile.clear(); after you close it.
Since C++11, this is done automaticaly by open(), though. If you're already using a C++11 compiler, your problem is elsewhere (can't say where, you haven't shown enough code).

Learn singleton design pattern for logging or any multiple access to any file. You can also use Mutex lock so that code will be waited for resources like files. But it is not wise to use same file simultaneously. File can be open for a lyfecycle of code. It is not a issue.

Related

Data isn't being saved in the text file (C++ Fstream library )

I've been trying to save the score of the player in the game in a text file, but it doesn't do so.
This is the code I'm using:
//some code above
std::fstream TextScore ("Ranking.txt");
// some code above
if (Player->getFinal(Map) == true)
{
TextScore.open("Ranking.txt", ios::out);
TextScore << Player->getPoints();
TextScore.close();
//some code below
}
Then I check the text file and nothing has been saved, the file is empty.
I would like to know what I'm missing or doing wrong.
Thanks in advance.
std::fstream TextScore ("Ranking.txt");
This opens the file, as if TextScore.open("Ranking.txt"), std::ios::in|std::ios::out) was called.
TextScore.open("Ranking.txt", std::ios::out);
This opens it again.
The combination is not going to work if the file already exists. The first open will succeed and the second one will fail. After that, all I/O operations will fail. Open it just once, either in the constructor or in a separate open call. The most idiomatic C++ way would be
{
std::fstream TextScore ("Ranking.txt", std::ios::out);
TextScore << Player->getPoints();
}
No need to close the file explicitly thanks to RAII.
Opening the same file twice is certainly going to cause problems. Move the definition of TextScore into the body of the if statement in place of the call to TextScore.open(). And then you can remove the call to TextScore.close(); the destructor will close the file.

Having trouble with fstream in Xcode

I'm having trouble validating the existence of REGISTER.txt for input purposes in a function (see below). My understanding is that if the file doesn't exist, then the file won't be opened and the file stream variable (inData) will be false. Thus, I can use that variable in an if/else statement to verify whether or not it opened. But even though REGISTER.txt is in the same directory as my .cpp file, my code still says that it wasn't opened.
Here's the thing though. When I run the same exact code in Dev-C++ compiler, it works fine and the file is found. Now, I understand compilers are different, but I don't understand what is causing the discrepancy here. My preferred IDE is Xcode, so I'd like to learn how to do I/O with files in Xcode.
Thanks in advance for the help.
P.S. My Xcode project references the file, so it's not like the project isn't connected with the file.
void ReadVehicleRegInfo(char& vehicleType, string& licensePlate,
int& modelYear, float& origTaxValue, bool& error)
{
ifstream inData;
string inputFile = "REGISTER.txt";
inData.open(inputFile.c_str()); //File contains registration info
if (!inData) {
//File does not exist. Exit function
cout << inputFile << " does not exist. Program will now terminate"
<< endl << endl;
error = true;
return;
} else {
//File exists - continue with program
cout << inputFile << " found";
}
inData.close();
}
In my main() function, I have the following code to signal to the user that an error has occurred:
if (error) {
//Function encountered error. Exits program
system("PAUSE");
return 99;
}
EDIT
I spent 40 minutes trying to figure this out, 15 writing the question, and 5 minutes after I post it I make huge progress. Don't you love that?
I put in the full directory to the file and that did the trick.
However, this is not ideal. The next question is how do I avoid having to do that? What is the default directory for Xcode?
Normally it would be the directory where your program lives. If you want to make sure, use _getcwd to get the current directory or just include the parent directory.
char *_getcwd(
char *buffer,
int maxlen
);
However, you should try not to use the full path for the reason it might not be the same when you run your program on another computer.
REGISTER.txt is in the same directory as my .cpp file
REGISTER.txt needs to be in the same directory as the binary (build/Release or elsewhere depending on your build settings)

C++ - ofstream doesn't output to file until I close the program

I have the following code:
ofstream mOutFile.open(logPath, ios_base::app);
string lBuilder;
lBuilder.append("========================================================\n");
lBuilder.append("Date: ");
lBuilder.append(asctime(timeinfo));
lBuilder.append("\n");
lBuilder.append("Log Message:\n");
lBuilder.append(toLog);
lBuilder.append("\n");
lBuilder.append("========================================================\n\n");
int lSize = lBuilder.size();
char* lBuffer = new char[lSize];
int index = 0;
for each (char c in lBuilder)
lBuffer[index++] = c;
mOutFile.write(lBuffer, lSize);
mOutFile.flush();
Unfortunately, until I close the app (I assume that closing the ofstream would work as well) the output does not get written to the text file. I know I could probably close and reopen the stream and everything will "just work" but that seems like a silly and incorrect solution. What am I doing wrong here?
I have also tried the following variations based on other questions I have found here, but these solutions did not work:
mOutputFile << flush;
mOutputFile << endl;
Thanks in advance for any assistance on this.
edit Everything in this code is working visual c++, it builds and works fine except the file is not written to until the stream is closed, even if I force a flush. Also, I switched from using the << operator to the char * and .write () to see if anything behaved differently.
std::ofstream file(logPath, ios_base::app);
file << "========================================================\n"
<< "Date: " << asctime(timeinfo)
<< "\nLog Message:\n" << toLog
<< "\n========================================================\n\n"
<< std::flush;
//if you want to force it write to the file it will also flush when the the file object is destroyed
//file will close itself
This is not only easier to read but it will probably also be faster than your method + it is a more standard appraoch
I ended up just "making it work" by closing and reopening the stream after the write operation.
mOutputFile << "all of my text" << endl;
mOutputFile.close();
mOutputFile.open(mLogPath);
EDIT After trying out forcing the flush on a few other systems, it looks like something just isn't performing correctly on my development machine. Not good news but at least the above solution seems to work when programmatically flushing the ofstream fails. I am not sure of the implications of the above code though, so if anyone wants to chime in if there are implications of closing and reopening the stream like this.
You can perform the following steps to validate some assumptions:
1.) After flush(), the changes to the file should be visible to your application. Open the file as std::fstream instead of std::ofstream. After flushing, reset the file pointer to the beginning and read the contents of the file. Your newly written record should be there. If not, you probably have a memory corruption somewhere in your code.
2.) Open the same file in an std::ifstream after your call to flush(). Then read the contents of the file. Your newly written record should be there. If not, then there's probably another process interfering with your file.
If both works, then you may want to read up on "file locking" and "inter-process syncronization". The OS can (theoretically) take as much time as it wants to make file changes visible to other processes.

Copying contents of one file to another in C++

I am using the following program to try to copy the contents of a file, src, to another, dest, in C++. The simplified code is given below:
#include <fstream>
using namespace std;
int main()
{
fstream src("c:\\tplat\test\\secClassMf19.txt", fstream::binary);
ofstream dest("c:\\tplat\\test\\mf19b.txt", fstream::trunc|fstream::binary);
dest << src.rdbuf();
return 0;
}
When I built and executed the program using CODEBLOCKS ide with GCC Compiler in windows, a new file named "....mf19.txt" was created, but no data was copied into it, and filesize = 0kb. I am positive I have some data in "...secClassMf19.txt".
I experience the same problem when I compiled the same progeam in windows Visual C++ 2008.
Can anyone please help explain why I am getting this unexpected behaviour, and more importantly, how to solve the problem?
You need to check whether opening the files actually succeeds before using those streams. Also, it never hurts to check if everything went right afterwards. Change your code to this and report back:
int main()
{
std::fstream src("c:\\tplat\test\\secClassMf19.txt", std::ios::binary);
if(!src.good())
{
std::cerr << "error opening input file\n";
std::exit(1);
}
std::ofstream dest("c:\\tplat\\test\\mf19b.txt", std::ios::trunc|std::ios::binary);
if(!dest.good())
{
std::cerr << "error opening output file\n";
std::exit(2);
}
dest << src.rdbuf();
if(!src.eof())
std::cerr << "reading from file failed\n";
if(!dst.good())
std::cerr << "writing to file failed\n";
return 0;
}
I bet you will report that one of the first two checks hits.
If opening the input file fails, try opening it using std::ios::in|std::ios::binary instead of just std::ios::binary.
Do you have any reason to not use CopyFile function?
Best
As it is written, your src instance is a regular fstream, and you are not specifying an open mode for input. The simple solution is to make src an instance of ifstream, and your code works. (Just by adding one byte!)
If you had tested the input stream (as sbi suggests), you would have found that it was not opened correctly, which is why your destination file was of zero size. It was opened in write mode (since it was an ofstream) with the truncation option to make it zero, but writing the result of rdbuf() simply failed, with nothing written.
Another thing to note is that while this works fine for small files, it would be very inefficient for large files. As is, you are reading the entire contents of the source file into memory, then writing it out again in one big block. This wastes a lot of memory. You are better off reading in chunks (say 1MB for example, a reasonable size for a disk cache) and writing a chunk at a time, with the last one being the remainder of the size. To determine the source's size, you can seek to the end and query the file offset, then you know how many bytes you are processing.
And you will probably find your OS is even more efficient at copying files if you use the native APIs, but then it becomes less portable. You may want to look at the Boost filesystem module for a portable solution.

Reading a stream in C++

I have the following code:
ifstream initFile;
initFile.open("D:\\InitTLM.csv");
if(initFile.is_open())
{
// Process file
}
The file is not opening. The file does exist on the D: drive. Is there a way to find out exactly why this file cannot be found? Like an "errno"?
You should be able to use your OS's underlying error reporting mechanism to get the reason (because the standard library is built on the OS primitives). The code won't be portable, but it should get you to the bottom of your issue.
Since you appear to be using Windows, you would use GetLastError to get the raw code and FormatMessage to convert it to a textual description.
Answered here I believe: Get std::fstream failure error messages and/or exceptions
The STL is not great at reporting errors. Here's the best you can do within the standard:
ifstream initFile;
initFile.exceptions(ifstream::eofbit|ifstream::failbit|ifstream::badbit);
try
{
initFile.open("D:\\InitTLM.csv");
// Process File
}
catch(ifstream::failure e)
{
cout << "Exception opening file:" << e.what() << endl;
}
In my experience, the message returned by what() is usually useless.
Check the permissions on the root of the D: drive. You may find that your compiled executable, or the service under which your debugger is running, does not have sufficient access privileges to open that file.
Try changing the permissions on the D:\ root directory temporarily to "Everyone --> Full Control", and see if that fixes the issue.