473,701 Members | 2,628 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

design question (converting class data to csv)

I have a class that I want to turn its contents into csv file. I want
to be able to set the value of the delimiter, the name of the file it
gets saved to, the path of that file, and maybe a few other things.
What would be a good design to accomplish these goals? Here are the
ideas that I have come up with:

Class X = class with data that I want to put into csv.

1. Nested Function Object
use a nested function object to do the conversion.
+ X does not get polluted with functions that really have no place.
e.g. setDelimeter()
+ behaves the way you would expect. e.g. X.toCsv() to convert X into a
csv file
- Setting state may not be clear to those not familar with function
objects e.g. X.toCsv.setDeli meter() Some may ask why a function is
being used like an object.

2. Create a class ConvertXToCsv that gets passed X to do the
conversion.
+ very straight forward and gets the job done.
- proliferation of classes.

Any suggestions?
-Thanks,

Jake

Oct 16 '06 #1
4 2048
<al******@gmail .comschrieb im Newsbeitrag
news:11******** **************@ k70g2000cwa.goo glegroups.com.. .
>I have a class that I want to turn its contents into csv file. I want
to be able to set the value of the delimiter, the name of the file it
gets saved to, the path of that file, and maybe a few other things.
What would be a good design to accomplish these goals? Here are the
ideas that I have come up with:

Class X = class with data that I want to put into csv.

1. Nested Function Object
use a nested function object to do the conversion.
+ X does not get polluted with functions that really have no place.
e.g. setDelimeter()
+ behaves the way you would expect. e.g. X.toCsv() to convert X into a
csv file
- Setting state may not be clear to those not familar with function
objects e.g. X.toCsv.setDeli meter() Some may ask why a function is
being used like an object.

2. Create a class ConvertXToCsv that gets passed X to do the
conversion.
+ very straight forward and gets the job done.
- proliferation of classes.
Writing data to a file (or whatever else) can be split into two tasks -
providing the data to be written and formating (and writing) data
"somewhere" .

The provider of your data usually doesn't care (or shouldn't) where its data
will be written to. To write data to a CSV file or some other record
oriented medium, a set of functions like OpenRecord, CloseRecord, WriteInt,
WriteString etc. are all your data source needs to write its data. Such
functions can easyly be defined by an (abstract) interface class.

The consumer of such data usually shouldn't know where its input comes from.
But it might need additional information like delimiters or filenames, which
cannot be supplied by the data source itself. Also, such additional
information depends on the type of medium where the (formated) data should
be written to. That information must be supplied by that part of a program,
that actually wants data to be written to a well-known medium.

Your second idea is a step into that direction, but the fixed connection of
a given class X and a single medium (CSV files) makes it difficult to write
data from another class, or to another medium. You would end with x*y
ConvertXToY classes, where x is the number of data classes to write and y
the number of supported media. With an abstract writer class used by all
data classes and implementations for different media, otoh, you only need y
classes and one additional function in each data class.

The C++ stream library is a small step in this direction, but it only
abstracts the representation of data streams (as a file, a string or a
console device).

Consider this small (incomplete and buggy) example:

class Writer
{
public:
virtual void OpenRecord() = 0;
virtual void CloseRecord() = 0;
virtual void Write(int) = 0;
virtual void Write(std::stri ng const&) = 0;
};

class CsvWriter: public Writer
{
// Implementation of Writer class
void OpenRecord()
{
first = true;
}
void CloseRecord()
{
file << std::endl;
}
void Write(int x)
{
NextField();
file << x;
}
void Write(std::stri ng const& x)
{
NextField();
file << '"' << x << '"';
}
public:
CsvWriter(char const* fn, char d)
: file(fn)
, delimiter(d)
{}
private:
void NextFiled()
{
if (!first) file << delimiter;
first = false;
}
private:
std::ofstream file;
char delimiter;
bool first;
};
class MyData
{
public:
...
void Write(Writer& writer)
{
writer.OpenReco rd();
writer.Write(na me);
writer.Write(ag e);
writer.CloseRec ord();
}
private:
std::string name;
int age;
};
int main()
{
MyData x;
MyData y;
...
CsvWriter datafile("dataf ile.csv", ';');
x.Write(datafil e);
y.Write(datafil e);
}

Regards
Heinz
Oct 16 '06 #2

al******@gmail. com wrote:
I have a class that I want to turn its contents into csv file. I want
to be able to set the value of the delimiter, the name of the file it
gets saved to, the path of that file, and maybe a few other things.
What would be a good design to accomplish these goals? Here are the
ideas that I have come up with:

Class X = class with data that I want to put into csv.

1. Nested Function Object
use a nested function object to do the conversion.
+ X does not get polluted with functions that really have no place.
e.g. setDelimeter()
+ behaves the way you would expect. e.g. X.toCsv() to convert X into a
csv file
- Setting state may not be clear to those not familar with function
objects e.g. X.toCsv.setDeli meter() Some may ask why a function is
being used like an object.

2. Create a class ConvertXToCsv that gets passed X to do the
conversion.
+ very straight forward and gets the job done.
- proliferation of classes.

Any suggestions?
-Thanks,

Jake
First item, if you have a class that needs to stream its members,
overload the global stream operator and make it a friend of the class.
That way you might one day come along and write a container class to
store all your X instances and you'll be able to stream the entire
container seamlessly using another overload of global op<<.

As far as conversion to csv and delimeters, all you are doing is
opening a std::ofstream to some specific file somewhere. Why not write
a container that will:
1. store your records into a well-known and common container (list,
vector, deque)
2. stream records around using std::ostreams for compatibility and
future expandeability
3. provide the container with a function to serialize the records to
file

I'ld suggest a new line at the end of each record to help later when
using getline(...) to read that file and load the container from file
records. A solution with exception handling would have been preferable
and error checking is kept to a minimum.
Since you have not shown your precious class, i've made one up called
X.
#include <iostream>
#include <ostream>
#include <string>
#include <vector>
#include <fstream>
#include <iterator// for std::ostream_it erator

class X
{
int n;
double d;
std::string s;
public:
X() : n(0), d(0.0), s() { }
X(int n_, double d_, std::string s_)
: n(n_), d(d_), s(s_) { }
/* member functions */
void serialize( std::ostream& ) const;
/* friends */
friend std::ostream& operator<<( std::ostream&, const X& );
};

void X::serialize(st d::ostream& os) const
{
os << n << '$' << d << '$' << s << std::endl;
}

std::ostream& operator<<(std: :ostream& os, const X& r_x)
{
os << "n = " << r_x.n;
os << "\nd = " << r_x.d;
os << "\ns = " << r_x.s << std::endl;
return os;
}

class XContainer
{
std::vector< X vx;
public:
XContainer() : vx() { }
void push_back( const X& r_x ) { vx.push_back( r_x ); }
size_t size() const { return vx.size(); }
/* member functions */
void serialize( std::ostream& ) const;
bool write( const std::string& ) const;
/* friends */
friend
std::ostream& operator<<( std::ostream&, const XContainer& );
};

void XContainer::ser ialize(std::ost ream& os) const
{
typedef std::vector< X >::const_iterat or VIter;
for (VIter xiter = vx.begin(); xiter != vx.end(); ++xiter)
{
(*xiter).serial ize(os);
}
}

bool XContainer::wri te(const std::string& r_filename) const
{
std::ofstream ofs(r_filename. c_str());
if ( !ofs.is_open() )
{
return true;
} else {
serialize(ofs);
}
return false;
}

std::ostream&
operator<<(std: :ostream& os, const XContainer& r_con)
{
std::copy( r_con.vx.begin( ),
r_con.vx.end(),
std::ostream_it erator< X >(os) );
return os;
}

int main()
{
XContainer xcontainer;
xcontainer.push _back( X(0, 0.0, "string 0") );
xcontainer.push _back( X(1, 1.1, "string 1") );
xcontainer.push _back( X(2, 2.2, "string 2") );
std::cout << xcontainer;

// show what file contents will look like on console
std::cout << "\nnumber of records = " << xcontainer.size ();
std::cout << std::endl;
xcontainer.seri alize( std::cout );

// write the records to file - write protect file to test
const std::string sfilename( "data.cvs" );
if ( xcontainer.writ e( sfilename ) )
{
std::cout << "\nerror: failed to open " << sfilename;
std::cout << " !!!\n";
} else {
std::cout << "\nsuccess: records written to " << sfilename;
std::cout << std::endl;
}

return 0;
}

/*
n = 0
d = 0
s = string 0
n = 1
d = 1.1
s = string 1
n = 2
d = 2.2
s = string 2

number of records = 3
0$0$string 0
1$1.1$string 1
2$2.2$string 2

success: records written to data.cvs
*/

Oct 16 '06 #3
On Mon, 16 Oct 2006 09:23:08 +0200, "Heinz Ozwirk" wrote:
>class MyData
{
public:
...
void Write(Writer& writer)
{
writer.OpenReco rd();
writer.Write(na me);
writer.Write(ag e);
writer.CloseRec ord();
}
private:
std::string name;
int age;
};
If you made Write() a non-member function you would completely
decouple class MyData from formatting and writing.

Best wishes,
Roland Pibinger

Oct 16 '06 #4

Salt_Peter wrote:
al******@gmail. com wrote:
I have a class that I want to turn its contents into csv file. I want
to be able to set the value of the delimiter, the name of the file it
gets saved to, the path of that file, and maybe a few other things.
What would be a good design to accomplish these goals? Here are the
ideas that I have come up with:

Class X = class with data that I want to put into csv.

1. Nested Function Object
use a nested function object to do the conversion.
+ X does not get polluted with functions that really have no place.
e.g. setDelimeter()
+ behaves the way you would expect. e.g. X.toCsv() to convert X into a
csv file
- Setting state may not be clear to those not familar with function
objects e.g. X.toCsv.setDeli meter() Some may ask why a function is
being used like an object.

2. Create a class ConvertXToCsv that gets passed X to do the
conversion.
+ very straight forward and gets the job done.
- proliferation of classes.

Any suggestions?
-Thanks,

Jake

First item, if you have a class that needs to stream its members,
overload the global stream operator and make it a friend of the class.
That way you might one day come along and write a container class to
store all your X instances and you'll be able to stream the entire
container seamlessly using another overload of global op<<.

As far as conversion to csv and delimeters, all you are doing is
opening a std::ofstream to some specific file somewhere. Why not write
a container that will:
1. store your records into a well-known and common container (list,
vector, deque)
2. stream records around using std::ostreams for compatibility and
future expandeability
3. provide the container with a function to serialize the records to
file

I'ld suggest a new line at the end of each record to help later when
using getline(...) to read that file and load the container from file
records. A solution with exception handling would have been preferable
and error checking is kept to a minimum.
Since you have not shown your precious class, i've made one up called
X.
#include <iostream>
#include <ostream>
#include <string>
#include <vector>
#include <fstream>
#include <iterator// for std::ostream_it erator

class X
{
int n;
double d;
std::string s;
public:
X() : n(0), d(0.0), s() { }
X(int n_, double d_, std::string s_)
: n(n_), d(d_), s(s_) { }
/* member functions */
void serialize( std::ostream& ) const;
/* friends */
friend std::ostream& operator<<( std::ostream&, const X& );
};

void X::serialize(st d::ostream& os) const
{
os << n << '$' << d << '$' << s << std::endl;
}

std::ostream& operator<<(std: :ostream& os, const X& r_x)
{
os << "n = " << r_x.n;
os << "\nd = " << r_x.d;
os << "\ns = " << r_x.s << std::endl;
return os;
}

class XContainer
{
std::vector< X vx;
public:
XContainer() : vx() { }
void push_back( const X& r_x ) { vx.push_back( r_x ); }
size_t size() const { return vx.size(); }
/* member functions */
void serialize( std::ostream& ) const;
bool write( const std::string& ) const;
/* friends */
friend
std::ostream& operator<<( std::ostream&, const XContainer& );
};

void XContainer::ser ialize(std::ost ream& os) const
{
typedef std::vector< X >::const_iterat or VIter;
for (VIter xiter = vx.begin(); xiter != vx.end(); ++xiter)
{
(*xiter).serial ize(os);
}
}

bool XContainer::wri te(const std::string& r_filename) const
{
std::ofstream ofs(r_filename. c_str());
if ( !ofs.is_open() )
{
return true;
} else {
serialize(ofs);
}
return false;
}

std::ostream&
operator<<(std: :ostream& os, const XContainer& r_con)
{
std::copy( r_con.vx.begin( ),
r_con.vx.end(),
std::ostream_it erator< X >(os) );
return os;
}

int main()
{
XContainer xcontainer;
xcontainer.push _back( X(0, 0.0, "string 0") );
xcontainer.push _back( X(1, 1.1, "string 1") );
xcontainer.push _back( X(2, 2.2, "string 2") );
std::cout << xcontainer;

// show what file contents will look like on console
std::cout << "\nnumber of records = " << xcontainer.size ();
std::cout << std::endl;
xcontainer.seri alize( std::cout );

// write the records to file - write protect file to test
const std::string sfilename( "data.cvs" );
if ( xcontainer.writ e( sfilename ) )
{
std::cout << "\nerror: failed to open " << sfilename;
std::cout << " !!!\n";
} else {
std::cout << "\nsuccess: records written to " << sfilename;
std::cout << std::endl;
}

return 0;
}

/*
n = 0
d = 0
s = string 0
n = 1
d = 1.1
s = string 1
n = 2
d = 2.2
s = string 2

number of records = 3
0$0$string 0
1$1.1$string 1
2$2.2$string 2

success: records written to data.cvs
*/
Thank you for the time put into your suggestions. I mean it.

There seems to be two different approaches to the design. Either tell
the class to serialize itself or Have a class whose purpose it is to
serialize classes. What are the design trade offs to each? From what I
understand of OOP (and I am some what of a newb so please if you can
help me understand) the idea is that the class knows about its
internals and it should be the only object that does. So telling the
class to serialize its self makes more sense to me be cause the class
knows what members it has and you telling that class to run operations
on it own data which is part of the reason for classes.

I am interested first if my assessment of the serialize method is
correct. Also, I am interested in knowing more about the benefits of
having a class that does the serialization as in Heinz's design.

Thanks

Oct 16 '06 #5

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

9
1699
by: chris | last post by:
I've been scripting with python for a while now. Basically writing a few functions and running in the ipython shell. That's been very useful. But the more I do this the more I see that I'm doing more or less the same thing over and over again. So its feels like I need to get into class programming with all its attendant benefits. However my biggest problem is a conceptual one. I just can't get my head around defining suitable classes, how...
0
1238
by: KS | last post by:
Hi, We are trying to do mail merge (Word 2000) from a SQL2000 server in a network environment. We has built a Web base Visual.Net project (C#) to query the SQL2000 database and format into a CSV format file. When someone click on a button on the webpage the CSV file is automatically generated on the webserver.
9
2497
by: Brian Henry | last post by:
If i inherite a queue class into my class, and do an override of the enqueue member, how would i then go about actually doing an enqueue of an item? I am a little confused on this one... does over ride just add aditional code ontop of the current class or completely over ride it in vb? I am use to C++ this is the first inherited thing I've done in VB.NET... I'm a little unsure of diffrences, could someone explain this to me some? thanks!
1
3746
by: Johanna Pfalz | last post by:
Is there a module/method in python to convert a file from .DBF format to ..CSV format? Johanna Pfalz
8
2234
by: Michael B. Trausch | last post by:
I was wondering if anyone has had any experience with this. Someone I know is trying to move away from Microsoft Works, and I am trying to look into a solution that would convert their data in a lossless fashion to a more modern format. The database has more than 65K rows, so converting it to be an Excel spreadsheet, would, AFAIK, not be an option. It would seem that MS Works can export the database as a DBF format database, though I...
1
1513
by: alacrite | last post by:
I have a class that represents a record in a database table. class tableName { int col1; string col2; int col3; ... other fields and relevant operations }
21
2010
by: py_genetic | last post by:
Hello, I'm importing large text files of data using csv. I would like to add some more auto sensing abilities. I'm considing sampling the data file and doing some fuzzy logic scoring on the attributes (colls in a data base/ csv file, eg. height weight income etc.) to determine the most efficient 'type' to convert the attribute coll into for further processing and efficient storage... Example row from sampled file data: , ....]
8
2358
by: =?Utf-8?B?eWRibg==?= | last post by:
I need to write a program validate a text file in CSV format. So I will have a class DataType and a lot of of derived class for various type, e.g. IntType, StringType, FloatType, MoneyType, ... etc. For each column of a type, it may accept null/empty value. or not. It may have various max length for StringType, IntType,... etc.
22
4019
by: Chuck Connors | last post by:
Hey guys. I'm working on a little program to help my wife catalog her/ our coupons. I found a good resource but need help formatting the text data so that I can import it into a mysql database. Here's the data format: 409220000003 Life Fitness Products $1 (12-13-08) (CVS) 546500181141 Oust Air Sanitizer, any B1G1F up to $3.49 (1-17-09) .35 each 518000159258 Pillsbury Crescent Dinner Rolls, any .25 (2-14-09) 518000550406 Pillsbury...
0
9229
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
9083
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
8977
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
8934
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
5904
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
4410
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
4662
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
3102
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
3
2035
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.