8 Replies - 740 Views - Last Post: 12 August 2019 - 02:33 PM Rate Topic: -----

#1 SynthesisAWE4UM   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 11
  • Joined: 17-June 19

My InventorySystem is revamped, need help w/sending data to .bin ~

Posted 08 August 2019 - 03:38 PM

Hi all,

It's been a while since I've posted here. In my last topic, I discussed some issues that I've been having with my InventorySystem codebase. I've overhauled the codebase so that it works sufficiently for my purposes. Now I just have a final building block to add onto it. I need help w/how to send my data to .bin. My data is a Packet object. Here's how I currently have it:

Don't worry about the "using namespace std" I know already. This is a quick project prototype...

Packet.h:

#ifndef PACKET_H
#define PACKET_H

#include <string>

using namespace std;

class Packet {
public:
	Packet() : partId(0), description("0"), price(0), partCount(0) {}
	Packet(int partId, string description, double price, int partCount) :
		partId(partId), description(description), price(price), partCount(partCount) {}
	int getPartId() const { return partId; }
	string getDescription() const { return description; }
	double getPrice() const { return price; }
	int getPartCount() const { return partCount; }
	Packet& operator=(const Packet &otherPacket) {
		if (&otherPacket != this) {
			partId = otherPacket.partId;
			description = otherPacket.description;
			price = otherPacket.price;
			partCount = otherPacket.partCount;
		}

		return *this;
	}
private:
	int partId;
	string description;
	double price;
	int partCount;
};

#endif



Main.cpp:

const string fileLocation = "PUT YOUR FILE LOCATION HERE";
const string binaryLocation = "PUT YOUR FILE LOCATION HERE";

void writeToBinary(BST<Packet> &data) {
	fstream bOutFile(binaryLocation, ios::out | ios::binary);
	BSTIterator <Packet> bstIterator(data);
	Packet rawPacket(0, "0", 0, 0);

	cout << "Starting to write packets to binary..." << endl;
	while (bstIterator.hasNext()) {
		rawPacket = bstIterator.next();
		bOutFile.write((char*)&rawPacket, sizeof(rawPacket));
	}
	bOutFile.close();

	cout << "...Successfully completed writing to binary." << endl;
}

int main() {
	cout << "----------------------------------------------------" << endl;
	cout << "Input and Output Filing System" << endl;
	cout << "----------------------------------------------------" << endl;
	BST<Packet> test;
	// readFromFile(test);
	writeToBinary(test);

	system("pause");
}


Please note that I've removed the unnecessary parts. I really want to hone in on how I can extract my data to a .bin binary format properly. I was told this way that I'm doing right now is not the proper way to do it. I found it from some YouTube tutorial. I'm not sure how I can do this simply (extraction to .bin)? Is there a way that's simple and not too much?

Don't worry about the BST and the BSTIterators. BST is a binary search tree, it's just a container storing my data Packets.
We are extracting its content by using the BSTIterator.next() which pulls out the next smallest Packet (smallest partId).
Now how can I extract the data of Packet into .bin binary format and save it onto my computer? That's the question.

Can't wait to wrap this up, please help me if you know how to do this, thanks so much!


Is This A Good Question/Topic? 0
  • +

Replies To: My InventorySystem is revamped, need help w/sending data to .bin ~

#2 jimblumberg   User is offline

  • member icon

Reputation: 5745
  • View blog
  • Posts: 17,601
  • Joined: 25-December 09

Re: My InventorySystem is revamped, need help w/sending data to .bin ~

Posted 08 August 2019 - 03:50 PM

What did you not understand from your other topics about this problem?

You can not directly "write" non-trivial classes (like std::string) to a file using binary read()/write().

Also you need to figure out the writing of the information in order to read the information. The read() is basically just the opposite of the write().


Jim
Was This Post Helpful? 0
  • +
  • -

#3 SynthesisAWE4UM   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 11
  • Joined: 17-June 19

Re: My InventorySystem is revamped, need help w/sending data to .bin ~

Posted 08 August 2019 - 04:07 PM

View Postjimblumberg, on 08 August 2019 - 03:50 PM, said:

What did you not understand from your other topics about this problem?

You can not directly "write" non-trivial classes (like std::string) to a file using binary read()/write().

Also you need to figure out the writing of the information in order to read the information. The read() is basically just the opposite of the write().


Jim
Yes, I know it's not correct. I'm wanting to correct this:

I don't need to read .bin. I only want to write .bin for now.

I was told that there are 2 approaches:

View PostSkydiver, on 09 July 2019 - 01:41 PM, said:

View PostSynthesisAWE4UM, on 09 July 2019 - 03:59 PM, said:

Do you know where I can find more information on doing it the correct way preferably for beginners? Where can I find such tutorials b/c. I really want to finish this ASAP.

I'm quite sure that there are some tutorial out there, but basically there are two approaches:
Approach 1: Piece by piece
Write out all the pieces inside the class out to the stream one at a time. For variable length pieces like strings, either write out the length before the data, or have a special marker to mark the end of the variable length data. Reading back in is just a matter of reading the data back into the pieces.

Approach 2: Fixed chunks followed by variable sized pieces
Write out the entire structure/class (like you were doing above), followed by the variable length pieces. As above, store the length, or use a special marker. Reading back is matter or reading in he big chunk, and the after that repairing the places where they used to be pointers. Placement new will be your new friend and/or worse enemy.

For a beginner, I recommend Approach 1 unless you discover performance is suffering.

View PostSynthesisAWE4UM, on 09 July 2019 - 03:59 PM, said:

Additionally, do you have any ways of improving this:
:
Or do you think it's fine the way it is?

For class project code, it is fine the way it is. For production quality code, you'll want to remove that recursion in case your tree becomes very tall, or somebody feeds you data in sorted order and you end up with essentially a linked list instead of a tree.
I'm wanting to try doing approach 1. Is there a name for this approach? Would you have any examples so I can know how to start?

"Write out all the pieces inside the class out to the stream one at a time." I'm unsure how to go about doing this. As well as this
"For variable length pieces like strings, either write out the length before the data, or have a special marker to mark the end of the variable length data."

Would you happen to have any examples/resources to go about coding this?
Was This Post Helpful? 0
  • +
  • -

#4 jimblumberg   User is offline

  • member icon

Reputation: 5745
  • View blog
  • Posts: 17,601
  • Joined: 25-December 09

Re: My InventorySystem is revamped, need help w/sending data to .bin ~

Posted 08 August 2019 - 04:29 PM

Okay so show the code where you're trying to write() the data to the file. A small complete program that is only trying to write the data would be the best.

Jim
Was This Post Helpful? 0
  • +
  • -

#5 jimblumberg   User is offline

  • member icon

Reputation: 5745
  • View blog
  • Posts: 17,601
  • Joined: 25-December 09

Re: My InventorySystem is revamped, need help w/sending data to .bin ~

Posted 08 August 2019 - 04:39 PM

Oh, and how are you going to tell that you wrote the data properly, not just some random garbage?

Jim
Was This Post Helpful? 0
  • +
  • -

#6 jimblumberg   User is offline

  • member icon

Reputation: 5745
  • View blog
  • Posts: 17,601
  • Joined: 25-December 09

Re: My InventorySystem is revamped, need help w/sending data to .bin ~

Posted 08 August 2019 - 05:42 PM

Also why did you decide to use a "binary" format instead of a "text" based format?

Jim
Was This Post Helpful? 0
  • +
  • -

#7 SynthesisAWE4UM   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 11
  • Joined: 17-June 19

Re: My InventorySystem is revamped, need help w/sending data to .bin ~

Posted 09 August 2019 - 04:38 PM

View Postjimblumberg, on 08 August 2019 - 04:29 PM, said:

Okay so show the code where you're trying to write() the data to the file. A small complete program that is only trying to write the data would be the best.

Jim
This is really it right now:
const string fileLocation = "FILELOCATION_PUTYOURSHERE";
const string binaryLocation = "FILELOCATION_PUTYOURSHERE";

void writeToBinary(BST<Packet> &data) { // NOTE: This here needs to be made proper so that it can save as a proper .bin format.
	fstream bOutFile(binaryLocation, ios::out | ios::binary);
	BSTIterator <Packet> bstIterator(data);
	Packet rawPacket(0, "0", 0, 0);

	cout << "Starting to write packets to binary..." << endl;
	while (bstIterator.hasNext()) {
		rawPacket = bstIterator.next();
		bOutFile.write((char*)&rawPacket, sizeof(rawPacket));
	}
	bOutFile.close();

	cout << "...Successfully completed writing to binary." << endl;
}

void writeToFile(BST<Packet> &data) { // NOTE: This is how I'm writing to .txt. I already know this part. This is here as an example.
	ofstream outFile(fileLocation);
	BSTIterator <Packet> bstIterator(data);
	Packet rawPacket(0, "0", 0, 0);

	cout << "Starting to write packets to file..." << endl;
	while (bstIterator.hasNext()) {
		rawPacket = bstIterator.next();

		outFile << "{" << endl;
		outFile << rawPacket.getPartId() << endl;
		outFile << rawPacket.getDescription() << endl;
		outFile << rawPacket.getPartCount() << endl;
		outFile << rawPacket.getPrice() << endl;
		outFile << "}" << endl << endl;
	}
	outFile.close();

	cout << "...Successfully completed writing to file." << endl;
}

int main() {
	cout << "----------------------------------------------------" << endl;
	cout << "Input and Output Filing System" << endl;
	cout << "----------------------------------------------------" << endl;
	BST<Packet> test;
	// IGNORE: readFromFile(test);
	writeToBinary(test);

	system("pause");
}



Where Packet's format is using the basic types (nothing special):

class Packet {
public:
	Packet() : partId(0), description("0"), price(0), partCount(0) {}
	Packet(int partId, string description, double price, int partCount) :
		partId(partId), description(description), price(price), partCount(partCount) {}
	int getPartId() const { return partId; }
	string getDescription() const { return description; }
	double getPrice() const { return price; }
	int getPartCount() const { return partCount; }
	Packet& operator=(const Packet &otherPacket) {
		if (&otherPacket != this) {
			partId = otherPacket.partId;
			description = otherPacket.description;
			price = otherPacket.price;
			partCount = otherPacket.partCount;
		}

		return *this;
	}
private:
	int partId;
	string description;
	double price;
	int partCount;
};


As you can see, for every Packet: export the partId (an int), description (a string), price (a double), partCount (an int) to .bin (one file). Repeat for every Packet in the BST container (saving to that same .bin file).
As I remember from someone, use of string to .bin may be problematic. Converting the string to a char. array and then exporting to .bin should serialize correctly

View PostSkydiver, on 09 July 2019 - 01:22 PM, said:

since all the memory used by the class is all adjacent to each other.


View Postjimblumberg, on 08 August 2019 - 05:42 PM, said:

Also why did you decide to use a "binary" format instead of a "text" based format?

Jim
Because this is a practice assignment that pretty much just says to save to .bin format. I have to do .txt and .bin (I already did .txt so now .bin is left) and that's basically it.
Was This Post Helpful? 0
  • +
  • -

#8 jimblumberg   User is offline

  • member icon

Reputation: 5745
  • View blog
  • Posts: 17,601
  • Joined: 25-December 09

Re: My InventorySystem is revamped, need help w/sending data to .bin ~

Posted 09 August 2019 - 05:41 PM

Quote

This is really it right now:

No, that is a complicated mess that is doing much more than trying to write some information to a file. Simplify the program so that it is only writing and preferably reading some data to a file.

Here is a sample of a small program that is trying to read and write to a binary file. Note: I am not doing any real error checking since this is just a "test" program. You will want to do serious error checking on a "production" program.

#include <iostream>
#include <string>
#include <fstream>
#include <vector>

// Using a simple structure to illustrate the principles.
struct Data {
	int partId;
	std::string description;
	double price;
	int partCount;

    // A  couple of overloads to simplify things.
    std::ostream& write(std::ostream& fout) const;
    std::istream& read(std::istream& fin);

};

std::ostream& Data::write(std::ostream& fout) const
{
    // Write out the partId number.
    fout.write(reinterpret_cast<const char*>(&partId), sizeof(partId));

    // This is where you need to decide on how you want to write out the string.


    // Write out the price of the item.
    fout.write(reinterpret_cast<const char*>(&price), sizeof(price));
    // Write out the number of parts on hand.
    fout.write(reinterpret_cast<const char*>(&partCount), sizeof(partCount));

    return fout;
}

std::istream& Data::read(std::istream& fin)
{
    // The read is the opposite of the write.
    fin.read(reinterpret_cast<char*>(&partId), sizeof(partId));

    // This is where you need to decide on how you want to read in the string.


    // Read in the price of the item.
    fin.read(reinterpret_cast<char*>(&price), sizeof(price));
    // Read in the number of parts on hand.
    fin.read(reinterpret_cast<char*>(&partCount), sizeof(partCount));

    return fin;
}

int main()
{
    std::ofstream fout("data.bin");

    std::vector<Data> myData{{192, "My Small Widget", 1.23, 190}, {1902, "My Big Widget", 345.43, 16}};

    std::cout << myData[0].partId << std::endl;

    myData[0].write(fout);
    myData[1].write(fout);

    fout.close();

    std::ifstream fin("data.bin");

    Data from_file;

    from_file.read(fin);
    std::cout << from_file.partId << std::endl;
    from_file.read(fin);
    std::cout << from_file.partId << std::endl;

}




You have also not answered my questions from posts 5 and 6.


Jim
Was This Post Helpful? 1
  • +
  • -

#9 SynthesisAWE4UM   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 11
  • Joined: 17-June 19

Re: My InventorySystem is revamped, need help w/sending data to .bin ~

Posted 12 August 2019 - 02:33 PM

View Postjimblumberg, on 09 August 2019 - 05:41 PM, said:

Quote

This is really it right now:

No, that is a complicated mess that is doing much more than trying to write some information to a file. Simplify the program so that it is only writing and preferably reading some data to a file.

Here is a sample of a small program that is trying to read and write to a binary file. Note: I am not doing any real error checking since this is just a "test" program. You will want to do serious error checking on a "production" program.

...

You have also not answered my questions from posts 5 and 6.


Jim
I'm not sure why you consider it a complicated mess. I removed a good chunk of the codebase (part of a larger project) and honed in on the binary writing parts. My Packet's data structure matches yours, it's just you exposed it more.

But the thing is, I actually realized I was sitting on the solution a few days ago when reading your post. I forgot about that and opened it up. The solution is actually more simple than I thought:

void archiveData(string myFile, vector<Part> *myList) {
	ofstream file(myFile.c_str()); // .c_str() returns the C-string version of the string object. Required to open the file if you stored the name in a string. 
	
	file << myList->size() << endl;    
	for (unsigned i = 0; i < myList->size(); i++) {        
		file << myList->at(i).getID() << endl << myList->at(i).getDescription() << endl;    
	}    
	file.close(); 
}


Now this is my attempt at replicating it:
void createArchive() {
	ofstream file(binaryLocation.c_str()); // .c_str() returns the C-string version of the string object. Required to open the file if you stored the name in a string. 
	file << bstInventory.size() << endl;

	BSTIterator <Packet> bstIterator(bstInventory);
	while (bstIterator.hasNext()) {
		getRawPacket = bstIterator.next();
		file << getRawPacket.getPartId() << endl << getRawPacket.getDescription() << endl << getRawPacket.getPrice() << endl << getRawPacket.getPartCount() << endl;
	}

	file.close();
}


Where BST's size function is really just:
size_t size() { return sizeof(this); }


I'm not sure if I replicated it right. But I really just want to wrap this up now so I can move on. I'm of the opinion of creating an STL version of this (it will be significantly easier) and also the thought that these things are really meant for long-term projects which I'm not trying to do right now.

I did answer your question #6 in a previous post:

"Because this is a practice assignment that pretty much just says to save to .bin format. I have to do .txt and .bin (I already did .txt so now .bin is left) and that's basically it. "

For question #5:

I would do it the standard way (how it's usually meant to be done). I never dealt with binary before but from seeing the solution a while ago, gave me a rough idea of how it should be done (correctly for my project).

Pretty much this is done for me (as of now). But I'd like to hear if you have any comments, improvement tips, etc. for the codes that I've just shown you. Otherwise I want to start on an STL version of this (which shouldn't be as complicated as this). Let me know.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1