I am writing a program for class wherein I need to call a function multiple times from "main.cpp" which takes an ofstream as a parameter, and the function itself needs to append new data to the end of the .txt file every time it's called (in this example I've made the data of type int for simplicity's sake).
What's been happening is that when the function gets called multiple times in main, it just overwrites everything instead of appending new data to the end of the file. I know everything else in my program works so I'm just going to strip it down to the bare bones as much as possible so that this isn't TL;DR. I have included
#include<fstream>
using namespace std;
in all of my files.
Here's the gist of it:
in main.cpp:
aClass* someClass = new aClass;
int data = 0;
...
ofstream myfile ("file.txt");
someClass->appendData(myfile, data);
...
in aClass.h:
void appendData(ofstream& myfile, int data);
in aClass.cpp:
void aClass::appendData(ofstream& myfile, int data){
if(myfile.is_open()){
myfile << data << "\n";
myfile.close();
}
else cout << "Couldn't open file";
}
If anyone could help me with this I'd appreciate it. For some reason they haven't had us touch fstreams in over a year and I'm not sure what the problem is here.
The call
myfile.close();
in appendData is not right. Any subsequent output operations on myfile are ignored.
Remove it from there.
You may add it in main but it is optional. The destructor will call close(). However, there is no harm if you call close() on the object if you are sure you are not going to use it to write into it any more
Related
I recently learnt that to read properly from a text file we use
while(file>>var1>>var2){
//do stuff with data
}
instead of
while(file){
file>>var1>>var2;
//do stuff with data
}
because the latter performs one extra read even after last data item is read and on the next read it is able to read the eof, so if we have something like std::vector<CLASSNAME>CLASSVECTOR, we end up having one extra entry in the vector, while if we use the first method it reads only till the last record.
My question is if how do I read till the last record in case of a binary file?
So if I have something like:
class class1 {
int a;
class2 obj2;
class3 obj3;
public:
void write_ binary(std::ofstream file) const;
void read_file(std::ifstream file);
//rest of class definition
};
And I write this class like so :
void class1::write_ binary(std::ofstream file) const {
file.write(reinterpret_cast<const char*>(&a),sizeof(a));
obj2.write_binary(file); //this writes the data in the same way using
reinterpret_cast to ofstream file
obj3.write_binary(file); //this writes the data in the same way using
reinterpret_cast to ofstream file
}
And also if I read the file like so :
void class1::read_file(std::ifstream file) {
file.read(reinterpret_cast<char*>(&a),sizeof(a));
obj2.read_binary(file); //this reads data for obj2 in the same way using
read() and reinterpret_cast
obj3.read_binary(file); //this reads data for obj3 in the same way using read() and reinterpret_cast
}
And if I want to store this data in a vector like so:
class1 obj1;
std::vector<class1>records;
while(file)
{
obj1.read_binary(file);
records.push_back(obj1);
//reset obj1 to initial state
}
I end up getting an extra record in vector records. I cannot use while(file>>obj1) since I want to use >> for cin.
Please explain how do I read from binary file without reading an extra record.
It's the same as your text example, the test on the file must be after the read not before.
for (;;)
{
obj1.read_binary(file);
if (!file) // did the previous read fail?
break; // if so quit the loop
records.push_back(obj1);
}
I am trying to create class that reading and writing to the same file in c++ using template function and I'm trying to realize the function read() that reading a char or int and returns it and when i tried to run it i got number like -998324343 please help :)
#include<iostream>
#include<fstream>
using namespace std;
template <class T>
class myFile
{
ifstream in;
ofstream out;
public:
myFile(char* fileName)
{
in.open(fileName);
if (!in.is_open())
throw"couldnt open file to reading";
out.open(fileName);
if (!out.is_open())
throw"couldnt open file to writing";
cout << read();
}
T read() {
T x;
in >> x;
return x;
}
};
int main()
{
try {
myFile<int> a("read.txt");
}
catch (char* msg) {
cout << msg << endl;
}
}
Your out and in refer to the same file. So when this happens:
in.open(fileName);
if (!in.is_open())
throw"couldnt open file to reading";
out.open(fileName);
Assuming fileName exists as a file, out will truncate the file, so it becomes empty. The subsequent in >> x; will fail (because the file is empty) and depending on the C++ standard you're compiling against, either x will get zeroed out (since C++11) or remain unmodified (until C++11). I'm assuming you're compiling pre-C++11, in which case what you see is whatever indeterminate value x was initialized with.
Not sure what you need out for, but you either want it to refer to a different file or open it in append mode.
Regardless of whether or not out is truncating the file, the >> operation can fail. If it fails, you will get garbage data (or 0). So you need to check the result of that operation.
Note: Everywhere you are using char* you should be using const char*. The conversion from string literal to char* is deprecated (if you compiled with warnings enabled, you would see this).
suppose I want to write in a .txt file in following format
start-----
-----A----
----------
-B--------
-------end
I've 3 functions that write the parts to file; start to A, A to B then B to end.
My function call are going to be in this order
Func1(starts writing from start of file)
{ }
Func2(needs pointer to position A for writing to file)
{ }
Func3(needs pointer to position B for writing to file)
{ }
Take Fun1 and Func2 for example, Func1 will end writing at A, but the problem is that Func2 needs to go forward from point A. How can I pass a pointer of position A to Func2 so that it'll be able to continue writing from position A in the file?
Since this is c++ we could use file stream object from the standard c++ library.
#include <iostream>
#include <fstream>
using namespace std;
void func1(ofstream& f)
{
f << "data1";
}
void func2(ofstream& f)
{
f << "data2";
}
int main () {
ofstream myfile ("example.txt");
if (myfile.is_open())
{
func1(myfile);
func2(myfile);
myfile.close();
}
else cout << "Unable to open file";
return(0);
}
However this approach is universal. When you are working with file, you get some file identificator. It could be a FILE struct, Win32 HANDLE etc. Passing that object between functions will allow you to continuously write the file.
Not sure how you're outputting to a file (using which output method), but normally, the file pointer keeps track itself where it is up to.
eg using fstream
ofstream outFile;
outFile.open("foo.txt");
if (outFile.good())
{
outFile<<"This is line 1"<<endl
<<"This is line 2"; // Note no endl
outFile << "This is still line 2"<<endl;
}
If you pass the outFile ofstream object to a function, it should maintain position in the output file.
Previously answered: "ofstream" as function argument
as the title suggests, I am having a problem with not being able to read from an input file after passing the ifstream object to a class function. Basically I'm trying to sort a list of numbers using a heap ADT implemented with an array.
int main() {
ifstream infile("input.txt");
HeapSort* heap = new HeapSort(20); // creates a heap (array) with size 20
heap->buildHeap(&infile);
return 0;
}
void HeapSort::buildHeap(ifstream* infile) {
int data;
while (infile >> data) {cout << data << endl;}
infile->close();
}
the error occurs in the conditional of the while loop inside buildHeap. The compiler can't recognize the operator ">>" between an 'int' and an 'ifstream' object. However, strangely enough, if I write that same while loop inside main(), it'll work just fine. Also of note is that if I remove the while loop, the compiler returns no errors. Meaning, simply the act of passing the ifstream object from main to buildHeap is OK.
Please avoid suggesting alternative ways of achieving this. I was asked to not use any special fstream functions like eof(). I can only use the ">>" operator to read from the desired file.
You're passing a pointer to a stream, so you need to dereference it:
while (*infile >> data)
If you want your code to look like what you say you did in main, then you pass a reference:
heap->buildHeap(infile);
//...
void HeapSort::buildHeap(ifstream& infile)
{
int data;
while (infile >> data) { ... }
infile.close();
}
I am trying to write pointers of a class into file and then reading it. Writing is just fine, but reading shows error of type conversion. Help please.
Take example of this(integer).. If we use int instead of int* then code executes but not fine.
#include<iostream>
#include<windows.h>
#include<fstream>
using namespace std;
void save(int *ptr)
{
ofstream data;
data.open("info.txt",ios::app);
if (data.is_open())
{
data<<ptr;
data.close();
}
else
{
cout << "Unable to open file";
}
}
int* loaddata()
{
ifstream data;
int ptr;
data.open("info.txt");
if (data.is_open())
{
while (!data.eof() )
{
data>>ptr;
}
data.close();
}
else
{
cout << "Unable to open file";
}
return ptr;
}
void main()
{
int a=0;
save(&a);
int *ptr=loaddata();
}
A pointer is just a memory address. You can write it just fine, as you said, but when you read it, it is still just a memory address. Unless the object that it was pointing to is at the exact same memory location when you read it, you will be "reading" a pointer to random data, which you cannot convert to the class of the object it was pointing to before.
It's like storing the location (lat/long) of a butterfly, then trying to find that butterfly just from that position. The butterfly is most likley in a completely different place now.
What you are trying is that was normally called serialization.
The idea is to write class instances ( all data contained ) and an ID which can be the address of the instance because this is a very well unique id. Your serialization library takes care that only one instance is written ( as only one data set is needed ) and all later writes of this instance are done only by writing the pointer.
Reading back is quite simple as well. You serialization library knows that it needs a instance of a class, generate a new one with the content as written before if not already done with the unique id ( maybe the pointer/address as mentioned before ). After that every try to get a "read pointer" results in setting the pointer the actual value of the new generated instance.
Have a look for serializer pattern or a concrete implementation like boost::serialize http://www.boost.org/doc/libs/1_58_0/libs/serialization/doc/index.html