Jump to content


 


Register a free account to unlock additional features at BleepingComputer.com
Welcome to BleepingComputer, a free community where people like yourself come together to discuss and learn how to use their computers. Using the site is easy and fun. As a guest, you can browse and view the various discussions in the forums, but can not create a new topic or reply to an existing one unless you are logged in. Other benefits of registering an account are subscribing to topics and forums, creating a blog, and having no ads shown anywhere on the site.


Click here to Register a free account now! or read our Welcome Guide to learn how to use this site.

Photo

C++ insert a USER DEFINED class into a file, then read it


  • Please log in to reply
3 replies to this topic

#1 chopficaro

chopficaro

  • Members
  • 68 posts
  • OFFLINE
  •  
  • Local time:07:29 PM

Posted 27 May 2009 - 12:24 AM

i'm trying to make a program that can insert a class into a file, the contents of which are USER DEFINED, those are the key words here, but im having trouble.
so to get started off, i tried to just get a function to accept a variable of its own class that is dynamically allocated
that seems to be the trouble, i get compiler errors at the point of defining the function that uses those dynamically allocated intergers, because the function cant SEE the integers, it makes sense that it would be blind untill runtime
the origional plan was to get this to work somehow and then:
ask the user how many ints he wants put into the file
the number of ints would be saved in file 1
then we would scan the ints from the user, and save them in file 2
then when it came time to read the ints back again, we would first read file 1 and
newInts = new int [whatsInFile1]
then read whats in file 2 into newInts


does anyone have any suggestions? is there another way of doing this? the ultimate goal is to allow the user to enter as many ints, floats, and strings that he wants into the file.

heres my code:

//exportimportstructdec.h
#include <iosfwd>
using namespace std;
class BinFileIO
{
	void PrintMemory();
	void PostOpenWrite(std::ofstream&,string);
	void ScanStruct();
	public:
	void ReadFile(string);
	void WrtFile(string,string);
	void AppFile(string,string);
	void NewInts();
};
//exportimportstructdef.cpp
#include <iostream>
#include <fstream>
#include <string>
#include "exportImportStructDec.h"
using namespace std;



void BinFileIO::NewInts()
{
	int * atarashiInts;
	atarashiInts = new int [4];
}

void BinFileIO::PostOpenWrite(ofstream& fileOpenWright,string openWriteMessage)
{
	cout << openWriteMessage;
	this->ScanStruct();
	if (fileOpenWright.is_open())
	{
		fileOpenWright.write (reinterpret_cast<char*>(this), sizeof(*this));
		fileOpenWright.close();
	}
	else cout << "\nUnable to open file for output\n";
}
void BinFileIO::ReadFile(string readFileName)
{
	ifstream filei;
	filei.open ((readFileName+".obj").c_str(), ios::in|ios::binary);
	if (filei.is_open())
	{
		filei.read(reinterpret_cast<char*>(this), sizeof(BinFileIO));
		this->PrintMemory();
	}
	else cout << "\nUnable to open file for input\n";
}

//function to write over a file with a new structure
void BinFileIO::WrtFile(string wrtFileName,string wrtMessage)
{
	ofstream fileo;
	fileo.open ((wrtFileName+".obj").c_str(), ios::out|ios::binary);
	this->PostOpenWrite(fileo,wrtMessage);
}

//function to append the end of a file with a new structure
void BinFileIO::AppFile(string appFileName,string appMessage)
{
	ofstream filea;
	filea.open ((appFileName+".obj").c_str(), ios::app|ios::binary);
	this->PostOpenWrite(filea,appMessage);
}

void BinFileIO::ScanStruct()
{
	cin >> this->atarashiInts[0] >> this->atarashiInts[1] >> this->atarashiInts[2] >> this->atarashiInts[3];
}

void BinFileIO::PrintMemory()
{
	cout<<"\nint1\n"<< this->atarashiInts[0]<<"\nint2\n"<< this->atarashiInts[1]<<"\nint3\n"<< this->atarashiInts[2]<<"\nint4\n"<< this->atarashiInts[3]<<"\n";
}
//exportimportstructmain.cpp
#include <iostream>
#include <fstream>
#include <string>
#include "exportImportStructDec.h"
using namespace std;

BinFileIO myGradesi,myGradeso,myGradesa;

//declare pointers to structures for file io:
BinFileIO * pMyGradeso=&myGradeso;
BinFileIO * pMyGradesa=&myGradesa;
BinFileIO * pMyGradesi;

int main ()
{
	BinFileIO objectBinIO;
	int choice;
	string opFile;
	string opMessage="\nplease enter 4 Grades separated by pressing enter\n";
	string menu="\ndo u want to \n1, read from the file, or \n2, write over the file or \n3, append the file or \n4, exit the program?\n";
	//give the user options:
	do
	{
		cout<<"please enter the file name";
		cin>>opFile;
		cout<<menu;
		cin>>choice;
		//option 1, read from the file:
		if (choice==1)
		{
			objectBinIO.NewInts();

			objectBinIO.ReadFile(opFile);
		}
		//option 2, write over the file:
		if (choice==2)
		{
			objectBinIO.NewInts();

			objectBinIO.WrtFile(opFile,opMessage);
		}
		//option 3, append the file:
		if (choice==3)
		{
			objectBinIO.NewInts();

			objectBinIO.AppFile(opFile,opMessage);
		}
	//option 4, exit:
	}while (choice!=4);
	return 0;
}

Edited by chopficaro, 27 May 2009 - 12:29 AM.


BC AdBot (Login to Remove)

 


#2 Billy O'Neal

Billy O'Neal

    Visual C++ STL Maintainer


  • Malware Response Team
  • 12,304 posts
  • OFFLINE
  •  
  • Gender:Male
  • Location:Redmond, Washington
  • Local time:05:29 PM

Posted 27 May 2009 - 12:55 AM

Hello :thumbsup:

C++ has no direct method of putting a class into a file.

Here's a major problem ->

void BinFileIO::NewInts()
{
int * atarashiInts;
atarashiInts = new int [4];
}


That int* is not known to the other functions in the class. You need to declare that item as a private instance member. You also need to make provisions for that dynamic array to be deleted.

As for insertion into a class, that would require code reflection, which C++ does not have provisions for. You cannot define a class at runtime -- you can only instantiate an existing one.

filei.read(reinterpret_cast<char*>(this), sizeof(BinFileIO));

This is generally an invalid concept for several reasons. First, classes may have extra compiler data appended to them, such as virtual function tables, which must not be saved. Second, such code makes your code byte order dependent -- and therefore is not portable. Third, you are not saving the ints you've dynamically allocated using such a method -- you are saving the pointer inside the class. When the class is reloaded that pointer would be meaningless.

What you basically need to do if you want code like this is to define a structure like this:

struct anyType {
enum {
INTEGER,
CHARACTER,
FLOATINGPOINT
} type;
union {
char c;
int i;
double f;
}
}

Save a double to the f item in the union, and set the type variable to FLOATINGPOINT. You can then copy this to a stream, and reload it, because the struct fits the C++ definition of Plain Old Data.

Hope that's helpful,

Billy3

Edited by Billy O'Neal, 27 May 2009 - 12:55 AM.

Twitter - My statements do not establish the official position of Microsoft Corporation, and are my own personal opinion. (But you already knew that, right?)
Posted Image

#3 chopficaro

chopficaro
  • Topic Starter

  • Members
  • 68 posts
  • OFFLINE
  •  
  • Local time:07:29 PM

Posted 27 May 2009 - 03:24 AM

if i understand you correctly i think i need to be writing arrays of this structure to the file, and i would only need one file because i could just keep reading the enum until i reach the end of the file and then i would know what to allocate for. ill try this. this is going to take a while because i haven't figured out how im going to do it in my head but i'll give it a shot, thank you. if it works ill try to mix string file io into the mix. maybe ill write a certain bit after im finished writing structures and then write the strings, so i know when to stop reading structures, and then start reading strings.

#4 groovicus

groovicus

  • Security Colleague
  • 9,963 posts
  • OFFLINE
  •  
  • Gender:Male
  • Location:Centerville, SD
  • Local time:06:29 PM

Posted 27 May 2009 - 09:13 AM

I am doing something similar to this as part of a bioinformatics tool. Basically, I am getting a set of results returned from a database search, and I have no idea what format they are going to be in until the query actually takes place. For instance, the search can return simply an ID and a DESCRIPTION, or it could return an ID, NAME, DESCRIPTION, ACCESSION, and SEQUENCE. My class contains an inner class that provides a type field, and a value filed. As each object it populated, it is dumped into an array. Once the array is populated, I can loop through and see how many strings there are, and how many ints there arem etc. etc. The nice thing is that I can define any sort of 'type' that I want. I can have a type 'foo' if I want.....




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users