Writing/Reading 2D array to Binary File C++ - c++

I am trying to write data from a 2D array into a binary file. I am only writing the data that has a value greater than 0. Therefore, if the data is is 0, it will not be written to the file. The data is as follows:
Level 0 1 2 3 4 5
Row 0 4 3 1 0 2 4
Row 1 0 2 4 5 0 0
Row 2 3 2 1 5 2 0
Row 3 1 3 0 1 2 0
void {
// This is what i have for writing to file.
ofstream outBinFile;
ifstream inBinFile;
int row;
int column;
outBinFile.open("BINFILE.BIN", ios::out | ios::binary);
for (row = 0; row < MAX_ROW; row++){
for (column = 0; column < MAX_LEVEL; column++){
if (Array[row][column] != 0){
outBinFile.write (reinterpret_cast<char*> (&Array[row][column]), sizeof(int)
}
}
}
outBinFile.close();
// Reading to file.
inBinFile.open("BINFILE.BIN", ios::in | ios::binary);
for (row = 0; row < MAX_ROW; row++){
for (column = 0; column < MAX_LEVEL; column++){
if (Array[row][column] != 0){
inBinFile.read (reinterpret_cast<char*> (&Array[row][column]), sizeof(int)
}
}
}
inBinFile.close();
}
All the data being read is being inserted into the first row, how can i get the data to load as i exited the program?

You are reading only when data is not equal zero, means that it gets locked with first zero. Once it reaches zero it stops reading.
Before "if command" read file to some other varaible then in if (variable != 0) Array[row][column] = variable.
If your Array is initialized with data, maybe take a look into setting position of your reading. So to set ok I have zero, I should read from another position next.

Binary files take a simple memory dump. I'm on a mac so I had to find a way to calculate the size of the array since sizeof(array name) doesn't return the memory size of the array for some reason (macintosh, netbeans IDE, xCode compiler). The workaround I had to use was:
to write the file:
fstream fil;
fil.open("filename.xxx", ios::out | ios::binary);
fil.write(reinterpret_cast<char *>(&name), (rows*COLS)*sizeof(int));
fil.close();
//note: since using a 2D array &name can be replaced with just the array name
//this will write the entire array to the file at once
Reading was the same. Since the examples from the Gaddis book I was using did not work correctly on Macintosh I had to find a different way to accomplish this. Had to use the following code snippet
fstream fil;
fil.open("filename.xxx", ios::in | ios::binary);
fil.read(reinterpret_cast<char *>(&name), (rows*COLS)*sizeof(int));
fil.close();
//note: since using a 2D array &name can be replaced with just the array name
//this will write the entire array to the file at once
Instead of just getting the size of the entire array you need to calculate the size of the entire array by multiplying the rows*columns for a 2d array then multiplying it by the size of the data type (since I used integer array it was int in this case).

Related

Moving through text file c++

I'm trying to save numbers from first txt file to second one in reversed order.
To be clear, inside 1st txt I have typed numbers from 1 to 10 (decimal notation). When I try to count them, I get 5 or 7, depending on what's between them (space or enter).
Then, another error is that inside 2nd txt program saves as much "0s" as dl's variable value is equal to instead of loaded numbers in reversed order.
I paste the whole code, because I don't know file operation rules good enough to determine which exact part could be the source of problem. Thank You in advance.
#include <fstream>
#include <iostream>
using namespace std;
int main() {
fstream plik1;
plik1.open("L8_F3_Z2a.txt", ios::in | ios::binary);
fstream plik2;
plik2.open("L8_F3_Z2b.txt", ios::out);
if(!plik1.good() || !plik2.good()) {
cout << "file(s) invalid" << endl;
return 1;
}
plik1.seekg(0, ios::end);
int dl = plik1.tellg() / sizeof(int);
cout << "length = " << dl << endl;
int a;
for(int i = 0; i < dl; i++) {
plik1.seekg((i + 1) * sizeof(int), ios::end);
plik1 >> a;
plik2 << a;
cout << i + 1 << ". a = " << a << endl;
}
plik1.close();
plik2.close();
return 0;
}
edit the output is:
length = 7
1. a = 0
2. a = 0
3. a = 0
4. a = 0
5. a = 0
6. a = 0
7. a = 0
--------------------------------
Process exited after 0.03841 seconds with return value 0
Press any key to continue . . .
Problem
When a file is encoded as text the binary size of the data is irrelevant.
int dl = plik1.tellg() / sizeof(int);
will get you the side of the file in integers, but the file isn't storing integers. It is storing a stream of characters. Say for example the file holds one number:
12345
which is five characters long. Assuming the file is using good ol ASCII, that's 5 bytes. When 12345 is converted to an int it will probably be 4 or 8 bytes and almost certainly not 5 bytes. Assuming the common 32 bit (4 byte) int
int dl = plik1.tellg() / sizeof(int);
int dl = 5 / 4;
int dl = 1;
Yay! It worked! But only by the grace of whatever deity or cosmic entity you worship. Or don't worship. I'm not going to judge. To show why you can't count on this, lets look at
123
this is three characters and 3 bytes, so
int dl = plik1.tellg() / sizeof(int);
int dl = 3 / 4;
int dl = 0;
Whoops.
Similarly
1 2 3 4 5
is five numbers. The file length will probably be the sum of one byte per digit and one byte per space, 9 bytes.
Where this gets weird is some systems, looking at you Windows, use a two character end of line marker, carriage return and a line feed. This means
1
2
3
4
5
will sum up to 13 bytes.
This is why you see a different size depending on whether the numbers are separated with spaces or newlines.
Solution
The only way to find out how many numbers are in the file is to read the file, convert the contents to numbers, and count the numbers as you find them.
How to do that:
int num;
int count = 0;
while (plik1 >> num) // read numbers until we can't read any more
{
count++;
}
From this you can determine the size of the array you need. Then you rewind the file, seek back to the beginning, allocate the array and read the file AGAIN into the array. This is dumb. File IO is painfully slow. You don't want to do it twice. You want to read the file once and store as you go without caring how many numbers are in the file.
Fortunately there are a number of tools built into C++ that do exactly that. I like std::vector
std::vector<int> nums;
int num;
while (plik1 >> num)
{
nums.push_back(num);
}
vector even keeps count for you.
Next you could
std::reverse(nums.begin(), nums.end());
and write the result back out.
for (int num: nums)
{
plik2 << num << ' ';
}
Documentation for std::reverse
If your instructor has a no vector policy, and unfortunately many do, your best bet is to write your own simple version of vector. There are many examples of how to do this already on Stack Overflow.
Addendum
In binary 5 integers will likely be 20 or 40 bytes no matter how many digits are used and no separators are required.
It sounds like storing data as binary is the bees knees, right? Like it's going to be much easier.
But it's not. Different computers and different compilers use different sizes for integers. All you are guaranteed is an int is at least 2 bytes and no larger than a long. All of the integer types could be exactly the same size at 64 bits. Blah. Worse, not all computers store integers in the same order. Because it's easier to do some operations if the number is stored backwards, guess what? Often the number is stored backwards. You have to be very, very careful with binary data and establish a data protocol (search term for more on this topic: Serialization) that defines the how the data is to be interpreted by everyone.

Vector is not acting as expected

I am trying to open a text file and pass the lines of the text file to a vector. The first digit in each line is the size of the vector and since I do not know the end point of the text file I am using a while loop to find the end. The idea is that I can take a text file and run a merge sort on it. So, for example:
3 5 4 9
5 0 2 6 8 1
sorted it would be become:
4 5 9
0 1 2 6 8
The problem I am having is that when I sort a vector that is larger than the prior vector (as in the example) I do not get output. It is probably something simple that I just have over looked. I am pretty sure the issue is in the code below. Thanks for any pointers.
while (!file.eof())
{
int size;
file >> size;
vector<int> myVector(size);
int n = 0;
while (n < size && file >> myVector[n])
{
++n;
}
sort(myVector);
for (int j = 0; j < size; ++j)
{
if (file.eof()) break;
cout << myVector[j] << ' ';
}
cout << '\n';
}
The problem is this line:
if (file.eof()) break;
Once you've read the last line of the file, file.eof() will be true. So the first time through the loop that's supposed to print the sorted vector, you break out of the loop and don't print anything. It has nothing do with whether the vector is larger than the previous vector, it's just a problem with the last line of the file. The fix is to get rid of that unnecessary line.
You also need to change the main loop. while (!file.eof()) is the wrong way to loop over a file's contents (see the linked questions for full explanations). Use:
int size;
while (file >> size) {
...
}
because of the line :
if(file.eof()) break;
if you get to eof your program wont print anything since you break the printing loop on its first iteration
for instance - if there are no chars after 8 in your example - you wont get output ,but even a single space can change that
besides that - is there any chance or cases that your sorting function clears a vector ? or changes it ?

Writing to a file column by column C++

i'm struggling to find a way to this and can't seem to find any solution anywhere, but I imagine it has to be possible.
I would like to write to a file, column by column instead of row by row.I have an arrays of strings which get updated as my program is running. The strings look like this "--4---" , "1-----", "--15---", "----6-" etc.
These need to be written to a file aligned column by column, from left to right. eg. :
--1-------
----------
4----15---
----------
-------6--
----------
I am using ofstream. I could wait until a certain number of strings are updated, then print them row by row to the file, but it gets messy when I have numbers with two digits , as have to correct offsets in advance (each array index must be aligned) etc.
Thanks for any help
A better method is to model the file in memory, then write the memory to the file.
If your text representation has 5 columns, I recommend using a matrix with 6 columns and let the 6th column be a newline.
#define MAX_ROWS 4
#define MAX_COLUMNS (5+1)
char board[MAX_ROWS][MAX_COLUMNS];
// Initialize the board
for (size_t row = 0; row < MAX_ROWS; ++row)
{
for (size_t column = 0; column < MAX_COLUMNS - 1; ++column)
{
board[row][column] = '-';
}
board[row][column] = '\n';
}
board[MAX_ROWS-1][MAX_COLUMNS-1] = '\0'; // Add terminating NULL.
You can then print the board by:
cout << (char *)(&board[0][0]) << endl;
Usually, writing to memory is a lot faster than writing to a file. Also, you can output the board in any format, such as CSV or XML.

File based input to define graph variables

I am currently trying to create a program in c++ that will allow a user to fill in a text file to define variables for a graph, these variables define the distance between nodes in the graph. The format is as follows:
int numberOfNodes
//node 0, node 1 , node 2
float distance1, distance2, distance3 //node 0
float distance1, distance2, distance3 //node 1
float distance1, distance2, distance3 //node 2
(number of nodes being 3) which is why there is a 3x3 grid, which would specify the distance between each node.
for contect:
filedata.txt
3
0 1 2
1 0 3
2 3 0
I understand that to use file input you use fstream, along with ifstream to select the file to open. What I dont understand is how to put this data into context.
How do i tell c++ that the first line will always be how many nodes there are in the list, then how would I tell c++ that anything under that first line is the data I want to fill into their own lists?
while (infile >> size)
{
cout <<"Total number of Verticies in Graph = "<< size << endl;
}
With input like that:
3
First read the number of rows, and go into a for loop:
infile >> numrows;
for(int row = 0; i < numrows; ++i) {
}
The subsequent input can be read as
0 1 2
1 0 3
2 3 0
infile >> distance1 >> distance2 >> distance3;
inside of the loop.

C++ won't read in scientific notation data from a .txt file

I am writing a program which is reading in an array from a text file which has both normal integers, and also multiple numbers that are in scientific notation, of the form: #.#####E##. Here is a few sample lines of the input .txt file:
21 -1 0 0 501 502 0.00000000000E+00 0.00000000000E+00 0.17700026409E+03 0.17700026409E+03 0.00000000000E+00 0. -1.
21 -1 0 0 502 503 0.00000000000E+00 0.00000000000E+00 -0.45779372796E+03 0.45779372796E+03 0.00000000000E+00 0. 1.
6 1 1 2 501 0 -0.13244216743E+03 -0.16326397666E+03 -0.47746002227E+02 0.27641406353E+03 0.17300000000E+03 0. -1.
-6 1 1 2 0 503 0.13244216743E+03 0.16326397666E+03 -0.23304746164E+03 0.35837992852E+03 0.17300000000E+03 0. 1.
And here is my program which simply reads in the text file and puts it into an array (or more specifically, a vector of vectors):
vector <float> vec; //define vector for final table for histogram.
string lines;
vector<vector<float> > data; //define data "array" (vector of vectors)
ifstream infile("final.txt"); //read in text file
while (getline(infile, lines))
{
data.push_back(vector<float>());
istringstream ss(lines);
int value;
while (ss >> value)
{
data.back().push_back(value); //enter data from text file into array
}
}
for (int y = 0; y < data.size(); y++)
{
for (int x = 0; x < data[y].size(); x++)
{
cout<<data[y][x]<< " ";
}
cout << endl;
}
// Outputs the array to make sure it works.
Now, this code works beautifully for the first 6 columns of the text file (these columns are entirely integers), but then it completely ignores every column 6 and higher (these are the columns containing scientific notation numbers).
I have tried redefining the vectors as both types double and float, but it still does the same thing. How can I get C++ to recognize scientific notation?
Thanks in advance!
Change int value; to double value; and also change your vector to double instead of int.
Better yet, since you have three declarations that must all be synchronized to the correct type, make an alias to that type like this: using DATA_TYPE = double; then declare your vectors and such like this: vector<vector<DATA_TYPE> > data;, DATA_TYPE value;, etc. That way if you change the type of the data for whatever reason, all your vector and variable declarations will update automatically, thus avoiding these kinds of bugs.