C++ Read specific parts of a file with start and endpoint - c++

I am serializing multiple objects and want to save the given Strings to a file. The structure is the following:
A few string and long attributes, then a variable amount of maps<long, map<string, variant> >. My first idea was creating one valid JSONFile but this is very hard to do (all of the maps are very big and my temporary memory is not big enough). Since I cant serialize everything together I have to do it piece by piece. I am planning on doing that and I then want to save the recieved strings to a file. Here is how it will look like:
{ "Name": "StackOverflow"}
{"map1": //map here}
{"map2": //map here}
As you can see this is not one valid JSON object but 3 valid JSONObjects in one file. Now I want to deserialize and I need to give a valid JSONObject to the deserializer. I already save tellp() everytime when I write a new JSONObject to file, so in this example I would have the following adresses saved: 26, endofmap1, endofmap2.
Here is what I want to do: I want to use these addresses, to extract the strings from the file I wrote to. I need one string which is from 0 to (26-1), one string from 26 to(endofmap1-1) and one string from endofmap1 to (endofmap2-1). Since these strings would be valid JSONObjects i could deserialize them without problem.
How can I do this?

I would create a serialize and deserialize class that you can use as part of a hierarchy.
So for instance, in rough C++ psuedo-code:
class Object : public serialize, deserialize {
public:
int a;
float b;
Compound c;
bool serialize(fstream& fs) {
fs << a;
fs << b;
c->serialize(fs);
fs->flush();
}
// same for deserialize
};
class Compound : serialize, deserialize {
public:
map<> things;
bool serialize(fstream& fs) {
for(thing : things) {
fs << thing;
}
fs->flush();
}
};
With this you can use JSON as the file will be written as your walk the heirarchy.
Update:
To extract a specific string from a file you can use something like this:
// pass in an open stream (streams are good for unit testing!)
std::string extractString(fstream& fs) {
int location = /* the location of the start from file */;
int length = /* length of the string you want to extract */;
std::string str;
str.resize(length);
char* begin = *str.begin();
fs->seekp(location);
fs->read(begin, length);
return str;
}

Based on you saying "my temporary memory is not big enough", I'm going to assume two possibilities (though some kind of code example may help us help you!).
possibility one, the file is too big
The issue you would be facing here isn't a new one - a file too large for memory, assuming your algorithm isn't buffering all the data, and your stack can handle the recursion of course.
On windows you can use the MapViewOfFile function, the MSDN has plenty of detail on that. This function will effectively grab a "view" of a section of a file - allowing you to load enough of the file to modify only what you need, before closing and opening a view at a later offset.
If you are on a different platform, there will be similar functions.
possibility two, you are doing too much at once
The other option is more of a "software engineering" issue. You have so much data then when holding them in your std::maps, you run out of heap-memory.
If this is the case, you are going to need to use some clever thinking - here are some ideas!
Don't load all your data into the maps. wherever the data is coming from, take a CRC, Index, or Filename of the data-source. Store that information in the map, and leave the actual "big strings" on the hard disk. - This way you can load each item of data when you need it.
This works really well for data that needs to be sorted, or correlated.
Process or load your data when you need to write it. If you don't need to sort or correlate the data, why load it into a map beforehand at all? Just load each "big string" of data in sequence, then write them to the file with an ofstream.

Related

How to write content of an object into a file in c++

I have a code in this format:
srcSAXController control(input_filename.c_str());
std::string output_filename = input_filename;
output_filename = "c-" + output_filename.erase(input_filename.rfind(XML_STR));
std:: ofstream myfile(output_filename.c_str());
coverage_handler handler(i == MAIN_POS ? true : false, output_filename);
control.parse(&handler);
myfile.write((char *)&control, sizeof(control));
myfile.close();
I want the content of object 'control' to be written into my file. How to fix the code above, so that content of the control object is written to the file.
In general you need much more than just writing the bytes of the object to be able to save and reload it.
The problem is named "serialization" and depending on a lot of factors there are several strategies.
For example it's important to know if you need to save and reload the object on the same system or if you may need to reload it on a different system; it's also fundamental to know if the object contains links to other objects, if the link graph is a simple tree or if there are possibly loops, if you need to support versioning etc. etc.
Writing the bytes to disk like the code is doing is not going to work even for something as simple as an object containing an std::string.

C++ Way to make a counter for instances when a variable in a file being read equals a user input

My specific program basically sparses through a csv file and asks for user input in the form of whether they would like to know how many times goods where delivered by Bike, Car, or Foot, all of this information is stored in the file being read. My issue is I don't know how to build a counter for the code so like when it sparse through the file looking for a string that matches the user input (Bike, Car, or Foot) and then counts all occurences and returns that value to display to the user. Here is my counter method right now that only returns zero and I have no clue what the logic i should use here is.
I also think it is important to mention that p is given by a getvariable method so p equals the user input
int transport::counttimes(string p)
{
ifstream inFile;
inFile.open("donationDataFixed.csv");
int c=0;
string s;
string piece;
while(s!=p)
{
stringstream data(s);
getline(data,piece,',');
getline(data,piece,',');
getline(data,piece,',');
getline(data,piece,',');
getline(data,piece,',');
getline(data,piece,',');
getline(data,piece,',');//transportation mode
if (s==p)
{
c=c+1;
}
}
return c;
}
If that is your entire source, then I can tell you that you never assign "s" a string value.
Since "s" never has a string value, your counter never increments, hence you will always return 0.
Also you don't have logic to parse the entire file. There are several ways to do this. You can look at this post for looping the entire file.
How To Parse String File Txt Into Array With C++
There are a plenty of ways parsing csv files. Your choice may depends on the libraries you are using/want to use (std, boost, ...)
A good post with pros and cons and several examples can be found here

How to use text file as local database

I have a data_base.txt file with the next structure:
1|client_name|id_client|account_client|balance|status
2|client_name|id_client|account_client|balance|status
Example:
1|John Doe|08913835P|053-323-192|120.00|active
Now I want to have the next four functions working with this file:
This function will add a new client to the .txt file
int newClient(string client_name, string id_client)
{
.....
}
This function will check if a client exists by checking id_client
int checkClient(string id_client)
{
// return true; (if client with that ID exists)
// return false; (if client not exists)
}
This function will get a specific value:
int getData(string field, string id_client)
{
// Example: if string field == 'balance' and id_client == '08913835P' then return '120.00'
// This example is done using above example data structure.
}
This function will modify data
int modifyData(string field, string data)
{
// This should work like the previous function but this function will edit specific values.
}
That's all, I had been Googling for hours and I can't figure out yet how to do this.
This is problematic and horribly inefficient if not done right.
The short answer is that, if the length of each line can change, then you need to completely rewrite the entire file to update the data. This would work, for example, if your program loaded the entire file into memory and then saved it after it was modified.
To update the file on disk, you have to impose some type of rule, such as every line must be the same length. This would mean setting a maximum length for all your fields, and padding those fields with spaces or some other character.
Using the latter technique, it should be possible to construct a new line of data (with padding), know the location of that line in the file (line number - 1 times the length of each line), jump to that location and then write the line.
Getting the data would be simpler but similar. Just determine the offset of the line and read it (you'll know how long the lines is). Strip any padding before presenting to the user.
Modifying a line would be similar to a combination of getting the data and writing the data. You'd just update the data between the two.

Delete content in a text file between two specific characters

I'm making a simple bug tracker and am using a text file as the database. Right now I'm reading in all the information through keys and importing them into specific arrays.
for (int i = 0; i < 5; i++)
{
getline(bugDB, title[i], '#');
getline(bugDB, importance[i], '!');
getline(bugDB, type[i], '$');
getline(bugDB, description[i], '*');
}
Here is what's in my (terribly unreadable) file
Cant jump#Moderate!Bug$Every time I enter the cave of doom, I'm unable
to jump.*Horse too expensive#Moderate!Improvement$The horses cost way
too much gold, please lower the costs.*Crash on startup#Severe!Bug$I'm
crashing on startup on my Win8.1 machine, seems to be a 8.1
bug.*Floating tree at Imperial March#Minimal!Bug$There is a tree
floating about half a foot over the ground near the crafting
area.*Allow us to instance our group#Moderate!Improvement$We would
like a feature that gives us the ability to play with our groups alone
inside dungeons.*
Output:
This works great for me, but I'd like to be able to delete specific bugs. I'd be able to do this by letting the user choose a bug by number, find the corresponding * key, and delete all information until the program reaches the next * key.
I'd appreciate any suggestions, I don't know where to start here.
There is no direct mechanism for deleting some chunk of data from the middle of the file, no delete(file, start, end) function. To perform such a deletion you have to move the data which appears after the region; To delete ten bytes from the middle of a file you'd have to move all of the subsequent bytes back ten, looping over the data, then truncate to make the file ten bytes smaller.
In your case however, you've already written code to parse the file into memory, populating your arrays. Why not just implement a function to write the contents of the arrays back to a file? Truncate the file (open in mode "w" rather than "w+"), loop over the arrays writing their contents back to the file in your preferred format, but skip the entry that you want to delete.
its only possible by manually copying the data from input file to output file and leaving out the entry you want to delete.
but: i strongly encourage the usage of some small database for keeping the informations (look at sqlite)
Also its a bad bugtracker if solving the bug means "delete it from database" (its not even is a tracker). give it a status field (open, refused, duplicate, fixed, working, ...).
Additional remarks:
use one array that keeps some structure with n informations and not n arrays.
please remind that someone may use your delimiter characters in the descriptions (use some uncommon character and replace its usage in saved text)
explanation for 1.:
instead of using
std::vector<std::string> title;
std::vector<int> importance;
std::vector<std::string> description;
define a structure or class and create a vector of this structure.
struct Bug{
std::string title;
int importance; // better define an enum for importance
std::string description;
};
std::vector<Bug> bugs;

Serializing structs

I'm working on a homework project and i'm trying to store inventory data into a file.
The inventory data size shouldn't be too large cause technically no one is going to really use it.
I need to write these contents to a file:
• Item Description
• Quantity on Hand
• Wholesale Cost
• Retail Cost
• Date Added to Inventory
I am going to need to make an interface that allows me to do this:
• Add new records to the file
• Display any record in the file
• Change any record in the file
Struct would be the easiest way to go about this imo. If I can just figure out how to read / write structs to a file this should be really easy.
If you could provide a small example on how to do this I would really appreciate it.
Thanks!
Ask your teacher, could you use boost library.
If yes, read boost serilization tutorial, it contains a simple examples: http://www.boost.org/doc/libs/1_38_0/libs/serialization/doc/tutorial.html
But if you want understand how to work with files, you should do this works without any help or boost.
If you want works with std::[io]fstreams you should decide what format you will support:
- text - for this case best way define operator<< and operator>> and use them for writing structure to file or reading;
- binary - your structure should be POD ( plain old data ) and doesn't should contain pointers - and you will use read and write streams methods.
example for binary file:
http://www.codeguru.com/forum/showthread.php?t=269648
If you don't mind really low level, you can just bit copy the structs in and out by casting a pointer to the struct to void* and using sizeof() to get the struct length. (IIRC their is a way to dump/read a void buffer to/from a file)
Note this ONLY works if the data has no pointers/references/etc.
I like C's IO better than C++'s so:
typedef struct { int hi; int mon; char[35] dat; } S;
S s;
S arr[22];
int f;
// write
f = open(/* I forget the args*/);
// one
if(sizeof(s) != write(f, &s, sizeof(s))) Error();
// many
if(sizeof(arr) != write(f, arr, sizeof(arr))) Error();
close(f);
// read
f = open(/* I forget the args*/);
// one
if(sizeof(s) != read(f, &s, sizeof(s))) Error();
// many
if(sizeof(arr) != read(f, arr, sizeof(arr))) Error();
close(f);
IOStream library does it
The ofstream class provides the interface to write data to files as output streams.
The ifstream class provides the interface to read data from files as input streams
Edit- Example
I would go with XML; it's structured, it's text based so you can look at it with any text editor.