-
File Manipulation
Guys,
I am needing a little help finding some information.
I am a VB programmer by day but I am also taking some C++ classes so I can maybe change languages, but C++ and I are not getting along.
What I need to do is to be able to read a comma delimited file from a C++ program. the format would be like so
"phone","last name","first Name","address"
"phone","last name","first Name","address"
"phone","last name","first Name","address"
and so on. I have searched the forum and found nothing that I can tell relates to reading files like this. I have used the fstream header before for reading numbers and doing stuff with them but an address will have spaces, and fstream stops on a space.
I also need to be able to append the file when a new record needs added.
Any help would be appreciated.
Jerel
-
My own implementation
Code:
#include <stdio.h>
#include <malloc.h>
#include <windows.h>
//Frees a buffer
void VirtualFreeHuge(char** pString, int uBound)
{
//free each of the items
for(int i = 0; i <= uBound; i++)
free(pString[i]);
//free the item itself
free(pString);
};
TCHAR** VirtualSplitString(TCHAR* pString, TCHAR sep, int& uBound)
{
unsigned long s = 0; unsigned long i = 0;
TCHAR** pArray = (TCHAR**)calloc(strlen(pString), sizeof(TCHAR*));
//allocate empty storage
//the first array
pArray[0] = (TCHAR*)calloc(1024, sizeof(TCHAR));
//separate an array...
while(*pString)
{
//go through the string, find position
if(*pString == sep)
{
i++;
s = 0; //current position
//allocate space for new input
pArray[i] = (TCHAR*)calloc(1024, sizeof(TCHAR));
}
else
{
//get the current character and set it
pArray[i][s] = *pString;
//increase character position
s++;
}
//increase string position
pString++;
}
uBound = ++i;
//return the pArray data type
return pArray;
};
int main(int argc, char* argv[])
{
CHAR sz[1024];
FILE* f = fopen("C:\\file.txt", "r");
while(fgets(sz, 1024, f))
{
int u;
char** s = VirtualSplitString(sz, ',', u);
for(int i = 0; i < u; i++)
printf("%s\n", s[i]);
VirtualFreeHuge(s, u);
}
fclose(f);
return 0;
}
fclose(f);
-
I'll write something that is (hopefully) easier to use tomorrow.
-
*bump*
made_of_asp: I appreciate you posting your code, but I have no idea what it is doing.
Does anyone else have an example or can you point me in the right direction cause I really lost on how to do this.
Jerel
-
Is it supposed to read in this exact file or should it be more generic?
-
The program is a pizza order program so the file would be like so.
"5551212","Doe","John","1212 Mockingbird Ln"
I need to be able to extract the info from within the quotes.
I have started by reading one char at a time and kina of parse it til I get to a '\n' char.
Is that the best way to do it. made_of_asp was using the malloc.h header which if I remember what that is, its for grabbing chucks of memory from the heap and such, but his code lost me.
I guess the answer is it could generic so it could read any comma-delimited file.
-
Well, specialized is easier to write and to use...
And especially to understand. You wouldn't want me to come up with nested vectors or vectors of maps.
Here's specialized code for you.
Code:
#include <algorithm> // container manipulation
#include <string> // easy strings
#include <vector> // growable array
using namespace std;
// struct representing one line of data in the file
struct file_entry
{
string sPhone;
string sLast;
string sFirst;
string sAddress;
};
// prototypes
void read_your_file(const string &strFilename, vector<file_entry> &out);
void split_string(const string &s, vector<string> & out, char split_at);
ostream & operator <<(ostream &os, const file_entry &fe);
istream & operator >>(istream &is, file_entry &fe);
int main(int argc, char *argv[])
{
// storage location for the data
vector<file_entry> vc;
// read in data
// call app like
// app data.txt
// where data.txt is the file you want to read
read_your_file(argv[1], vc);
// output the array
for(vector<file_entry>::iterator it = vc.begin(); it != vc.end(); ++it)
cout << *it << '\n';
// ensure data is displayed
cout.flush();
return 0;
}
// this takes a string and splits it into an array of smaller strings
// it's splitted every time split_at is encountered
void split_string(const string &s, vector<string> & out, char split_at)
{
// for searching the string
string::const_iterator stay, run;
// set stay to the start of the string
stay = s.begin();
// temporary
string t;
// loop run through the string, from front to back
for(run=stay; run != s.end(); ++run)
{
// if encountered split char...
if(*run == split_at)
{
// ...clear the temporary value...
t.clear();
// (speeds it up a little)
t.reserve(run-stay);
// ..., copy current substring to temporary...
copy(stay, run, back_inserter(t));
// ...and add it to the array.
out.push_back(t);
// Finally, let the next substring begin directly after the splitting char.
stay = run+1;
}
}
// same as above for the last piece (from last split char to end of string)
t.clear();
t.reserve(run-stay);
copy(stay, run, back_inserter(t));
out.push_back(t);
}
// reads in one file_entry from any stream
istream & operator >>(istream &is, file_entry &fe)
{
// temporary
string t;
// read one line from the stream
getline(is, t);
// receives substrings
vector<string> vs;
// split the line
split_string(t, vs, ',');
// fill the struct
// substr removes the "
fe.sPhone = vs[0].substr(1, vs[0].size()-2);
fe.sLast = vs[1].substr(1, vs[1].size()-2);
fe.sFirst = vs[2].substr(1, vs[2].size()-2);
fe.sAddress = vs[3].substr(1, vs[3].size()-2);
return is;
}
// output a file_entry to a stream
ostream & operator <<(ostream &os, const file_entry &fe)
{
return os << fe.sPhone.c_str() << ' ' << fe.sLast.c_str() << ' '
<< fe.sFirst.c_str() << ' ' << fe.sAddress.c_str();
}
// read in a file of your format
void read_your_file(const string &strFilename, vector<file_entry> &out)
{
// the stream
ifstream ifs;
// open the file
ifs.open(strFilename.c_str());
// temporary
file_entry t;
// while the end is not reached
while(!ifs.eof()) {
// read in one entry
ifs >> t;
// and add it to the array
out.push_back(t);
}
}
-
I really appreciate it.
I am going to take this and fire it into my program and see how it works. It will probably be tomorrow before I can get back to you on it.
When and if I have questions, would you be willing to answer them for me when the time comes. I am wanting to understand what it does and I see your comments. Just want to be sure I understand what I am going to turn in.
Jerel
-
-
CB,
When I compile the program I get an error on the t.clear statements.
I also added the fstream header in there. Did you have the fstream header included as well?
I get an error 2039 on the t.clear() lines.
-
This is strange. Are you sure you included <string> and not <string.h>?
If it won't work you can alternativly write
t = "";
but this is less efficient than the clear call.
-
CB,
I still have not been able to get this to compile and run. I changed the t.clear to t = "" then I got an error 4786
I figured out what the error was and added:
#pragma warning(disable:4786) to my code
Now I have this
c:\program files\microsoft visual studio\vc98\include\iterator(82) : error C2039: 'push_back' : is not a member of 'basic_string<char,struct std::char_traits<char>,class std::allocator<char> >'
c:\program files\microsoft visual studio\vc98\include\iterator(82) : while compiling class-template member function 'class std::back_insert_iterator<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > &_
_thiscall std::back_insert_iterator<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >::operator =(const char &)'
Error executing cl.exe.
Do you have any ideas here.
I think I understand what the code is doing and if I code run it and step through it, I would be ok.
Jerel
ps
just to be safe here is the code I am running. It is the same code you posted with the exceptions of the t.clear, two more header files, and the pragma statement
Code:
#pragma warning(disable:4786)
#include <algorithm> // container manipulation
#include <string> // easy strings
#include <vector> // growable array
#include <fstream>
#include <iostream>
using namespace std;
// struct representing one line of data in the file
struct file_entry
{
string sPhone;
string sLast;
string sFirst;
string sAddress;
};
// prototypes
void read_your_file(const string &strFilename, vector<file_entry> &out);
void split_string(const string &s, vector<string> & out, char split_at);
ostream & operator <<(ostream &os, const file_entry &fe);
istream & operator >>(istream &is, file_entry &fe);
int main(int argc, char *argv[])
{
// storage location for the data
vector<file_entry> vc;
// read in data
// call app like
// app data.txt
// where data.txt is the file you want to read
read_your_file(argv[1], vc);
// output the array
for(vector<file_entry>::iterator it = vc.begin(); it != vc.end(); ++it)
cout << *it << '\n';
// ensure data is displayed
cout.flush();
return 0;
}
// this takes a string and splits it into an array of smaller strings
// it's splitted every time split_at is encountered
void split_string(const string &s, vector<string> & out, char split_at)
{
// for searching the string
string::const_iterator stay, run;
// set stay to the start of the string
stay = s.begin();
// temporary
string t;
// loop run through the string, from front to back
for(run=stay; run != s.end(); ++run)
{
// if encountered split char...
if(*run == split_at)
{
// ...clear the temporary value...
t = "";
// (speeds it up a little)
t.reserve(run-stay);
// ..., copy current substring to temporary...
copy(stay, run, back_inserter(t));
// ...and add it to the array.
out.push_back(t);
// Finally, let the next substring begin directly after the splitting char.
stay = run+1;
}
}
// same as above for the last piece (from last split char to end of string)
t = "";
t.reserve(run-stay);
copy(stay, run, back_inserter(t));
out.push_back(t);
}
// reads in one file_entry from any stream
istream & operator >>(istream &is, file_entry &fe)
{
// temporary
string t;
// read one line from the stream
getline(is, t);
// receives substrings
vector<string> vs;
// split the line
split_string(t, vs, ',');
// fill the struct
// substr removes the "
fe.sPhone = vs[0].substr(1, vs[0].size()-2);
fe.sLast = vs[1].substr(1, vs[1].size()-2);
fe.sFirst = vs[2].substr(1, vs[2].size()-2);
fe.sAddress = vs[3].substr(1, vs[3].size()-2);
return is;
}
// output a file_entry to a stream
ostream & operator <<(ostream &os, const file_entry &fe)
{
return os << fe.sPhone.c_str() << ' ' << fe.sLast.c_str() << ' '
<< fe.sFirst.c_str() << ' ' << fe.sAddress.c_str();
}
// read in a file of your format
void read_your_file(const string &strFilename, vector<file_entry> &out)
{
// the stream
ifstream ifs;
// open the file
ifs.open(strFilename.c_str());
// temporary
file_entry t;
// while the end is not reached
while(!ifs.eof()) {
// read in one entry
ifs >> t;
// and add it to the array
out.push_back(t);
}
}
-
What compiler are you using? push_back is (just as clear btw) a part of standard C++.
Could it be that some other header named <string> takes precedence over the one you want?
-
Oh, I see, VC++6 doesn't compile it...
I'll see what can be done.
-
Replace the split_string function by this:
Code:
// this takes a string and splits it into an array of smaller strings
// it's splitted every time split_at is encountered
void split_string(const string &s, vector<string> & out, char split_at)
{
// for searching the string
string::const_iterator stay, run;
// set stay to the start of the string
stay = s.begin();
// temporary
string t;
// loop run through the string, from front to back
for(run=stay; run != s.end(); ++run)
{
// if encountered split char...
if(*run == split_at)
{
// ...clear the temporary value...
t.erase();
// (speeds it up a little)
t.reserve(run-stay);
// ..., copy current substring to temporary...
t.append(stay, run);
// ...and add it to the array.
out.push_back(t);
// Finally, let the next substring begin directly after the splitting char.
stay = run+1;
}
}
// same as above for the last piece (from last split char to end of string)
t.erase();
t.reserve(run-stay);
t.append(stay, run);
out.push_back(t);
}
Stupid VC++6 *mumble*...
-
that did it. and the wild thing is I understand what it is doing.
and to think of all those curse words I have said about c++ :)
Thanks again,
Jerel
-
By The way, whats wrong with my method? It does exactly what you wanted.
It splits "AAA","BBB","CCCCCCCC" separatly.
-
I only splits, and doesn't read a file or anything.
And if it's only about splitting then strtoc is easier - and it doesn't ask the user to free any memory.
And finally it is pure C while mine is C++ and takes advantage of various C++ features, namely string and vector.
-
CB,
I am having a bit of trouble with this code for some reason. I basically have your code but I have changed it just a bit to make it my own and to help me understand it better.
anyway, the problem is, when I call the Parse function, the program crashes and if I debug it, I get a fatal exception. I dont have anything different than you. Its crashing when I pass the values to the function. I have look on here and read the books I have and I dont anything wrong.
here is the prototype
Code:
void ParseString(const string &, vector<string> &);
here is the function
Code:
void ParseString(const string &strParse, vector<string> &v)
{
// This sub will parse the string and add it to the vector
// We are passing by reference the string to parse and
// the vector to store it in
string::const_iterator start,stop; //This will help count through the string
string sTemp; //Temp string for storing the parsed variable
stop = strParse.begin(); //Set this to the fron of the string
//This loop will parse strParse. It will look for the comma and grab
//everything between start and stop until wee reach the end of the line
for (start = stop; start != strParse.end(); start++ )
{
//See if we are ready to parse
//typcast the ',' so we cansave some memory
if ( *start == char(',') ) //If where we are looking is a comma, then time to parse
{
sTemp.erase(); //Make sure we are empty
sTemp.reserve(start-stop); //Reserve the right memory.
sTemp.append( stop, start ); //Copy out what we need
v.push_back( sTemp ); //Add the new sting to the vector
stop = start + 1; //Move the pointer past the comma
}
//When we exit the loop, we will need to grab he last of the line
sTemp.erase(); //Make sure we are empty
sTemp.reserve(start-stop); //Reserve the right memory.
sTemp.append( stop, start ); //Copy out what we need
v.push_back( sTemp ); //Add the new sting to the vector
}
}
and here is how I call it, and how the variable are declared
Code:
string temp;
vector<string> tempVector;
ParseString( temp, tempVector );
I just dont understand why its crashing
Jerel
-
I don't either. Give me the whole code (or better, zip up the whole project) and post it, I'll take a look on it tomorrow or tuesday.
-
1 Attachment(s)
There it is. I only added the .cpp and the text file I am using.
I changed the file so it had no "" in the fields. Mainly just to give me a chance to play with the code and make it different so I could understand it better. Its far from finished but it is getting there.
Thanks,
Jerel
-
CB,
I deleted the byref variable and then readded them one at a time to see what was causing the problem and it started working. I eyeballed the code to death, maybe there was something not quite right.
I dont know but it is working now.
Thanks for the time you've given me,
Jerel
-
Hi CornedBee, is the following library is belong to WTL? as you use in your sample code.
PHP Code:
#include <algorithm> // container manipulation
#include <string> // easy strings
#include <vector> // growable array
using namespace std;
-
No, that's the Standard C++ Library. They used to be called the STL and people will recognise that, but technically they're not really that anymore.
-
Which mean i can call it from my C/C++ program? What is the binary dlls file for this STL library? As im new in WTL/STL/ATL
-
Which DLLs it is in may not apply. You might not be on Windows, you might be statically linking, whatever.
Note. STL is different from ATL and WTL, i.e. it's actually standardised, so you know it works on *all* systems......or should ;)
Mostly, the STL code is templates anyway, so it will be included directly into your program.