I've been struggling with the concept of unformatted I/O. My course textbook doesn't explain it well. It gives the small program but I don't know what is happening here. If someone could explain it to me, I would appreciate it
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main() {
const unsigned int size = 10;
int arr[size];
ifstream infile("small.ppm");
infile.read(reinterpret_cast<char *>(&arr), size * sizeof(arr[0]));
infile.close();
ofstream outfile("newfile.ppm");
outfile.write((char *)&arr, size * sizeof(arr[0]));
outfile.close();
}
What do the read() and write() functions do exactly. I understand that they must
take in (char *, buffer_size) as arguments, but what do the functions themselves do?
Also, once I read in the data with read(), how do I store that data and manipulate it?
Sorry that this is such a long question. I've been struggling with this concept for a while now. Thanks a lot for your help
but what do the functions themselves do?
These are writing/reading the data as a byte by byte copy to/from the binary file.
Also, once I read in the data with read(), how do I store that data and manipulate it?
You already stored a int arr[size];. You can manipulate that data using that int array.
Pitfalls:
If that data was serialized on a different machine, you'll notice endianess issues regarding the machine specific int representation.
Related
I'm having a little trouble figuring out how to write this value to a file correctly. I did a little research on the internet and found this article.
http://www.eecs.umich.edu/courses/eecs380/HANDOUTS/cppBinaryFileIO-2.html
#include <fstream>
#include <iostream>
int main()
{
int testVar = 71;
std::ofstream outputFile;
outputFile.open("C:/binary.dat", std::ios::out | std::ios::binary);
outputFile.seekg(0);
outputFile.write(&testVar, sizeof(testVar));
outputFile.close();
}
What I understand from the article is that the first parameter is a void pointer? which means that it will accept any type? But when I'm typing it out, the intelisense says there is no overload and the first parameter takes type char*.
Am I using the wrong header or something from an older C++ version??
Could really use some help here.
Thanks!
I am not familiar with the history of development of the functions. Hence, I can't comment on why the arguments are of type char* and not void*.
To solve your problem...
You can use:
outputFile.write(reinterpret_cast<char*>(&testVar), sizeof(testVar));
Use reinterpret_cast while using istream::read() also.
You really just need to cast it to char* like was said before, but there are other problems with the code.
seekg() is for input streams, and you are writing an output file. If you meant to clear the line, just open the file with trunc.
#include <fstream>
#include <iostream>
int main()
{
int testVar = 71;
std::ofstream outputFile("C:/binary.dat", std::ios::out | std::ios::binary | std::ios::trunc);
outputFile.write((char*)&testVar, sizeof(testVar));
outputFile.close();
}
The first parameter is a char*.
char having size 1 byte signifies byte by byte data and char* signifies a block of data.
Hence when writing raw binary data, the data is passed as a char* and size of the block.
Am I using the wrong header or something from an older C++ version??
No it is not the problem as stated it is char* and not void* that is taken as argument.
NOTE The seekg() member function is for input streams. I think the functionality you needed was seekp()
Today in CS 111 class my instructor ended with a 'brief' look at writing structures to binary files. I say brief because he just included it as a kind of aside, saying it would not be on the final. Problem is, I don't fully understand what's going on in the program example and it is bothering me. Hopefully somebody will take the time to explain it to me. The code is as follows:
#include <iostream>
#include <fstream>
using namespace std;
struct PayStub
{
int id_num;
bool overtime;
float hourly_rate;
};
int main()
{
PayStub info = {1234, false, 15.45};
ofstream data_store;
data_store.open("test.cs111", ios::binary);
char *raw_data = (char*)&info;
data_store.write(raw_data, sizeof(PayStub));
data_store.close();
return 0;
}
I don't understand what is going on specifically in the statement char *raw_data = (char*)&info; and why it is necessary. I understand a pointer to a char is being declared and initialized, but what exactly is it being initialized to, and how is that being used in the next line?
I hope this isn't a stupid question. Thanks in advance for your help.
char *raw_data = (char*)&info; after this line, raw_data will point to the address of the first byte of info.
With data_store.write(raw_data, sizeof(PayStub)); we ask data_store to write to the file the contents in memory that start at raw_data and end at raw_data + sizeof(PayStub)).
In essence we find the start address and length of PayStub and write it to disk.
It is not a stupid question. Once you read up on pointers, everything will make sense.
Think of a struct (in plain C) to simply be a way of binding a bunch of objects together with "string".
An int could be represented in memory with 4 bytes. A struct composed of two ints would be 8 bytes, one int next to the other.
In your example code, &info returns the pointer to the beginning of the object in memory, and (char*)&info simply interprets as a pointer to a character instead, so it can be treated as a sequence of binary data. sizeof returns how much memory (in bytes) the struct takes, and with this information the structure is then written directly to a file from memory.
Keep in mind this type of data storage is absolutely not portable. It might vary from a 32-bit to a 64-bit computer!
I have a very simple question, which happens to be hard for me since this is the first time I tried working with binary files, and I don't quite understand them. All I want to do is write an integer to a binary file.
Here is how I did it:
#include <fstream>
using namespace std;
int main () {
int num=162;
ofstream file ("file.bin", ios::binary);
file.write ((char *)&num, sizeof(num));
file.close ();
return 0;
}
Could you please tell me if I did something wrong, and what?
The part that is giving me trouble is line with file.write, I don't understand it.
Thank you in advance.
The part that is giving me trouble is line with file.write, I don't
understand it.
If you read the documentation of ofstream.write() method, you'll see that it requests two arguments:
a pointer to a block of data with the content to be written;
an integer value representing the size, in bytes, of this block.
This statement just gives these two pieces of information to ofstream.write():
file.write(reinterpret_cast<const char *>(&num), sizeof(num));
&num is the address of the block of data (in this case just an integer variable), sizeof(num) is the size of this block (e.g. 4 bytes on 32-bit platforms).
How do I read a binary file into a bitset or vector<bool>? The binary file will vary in length. Is there a better container for this? I am new to C++ though experienced as a programmer.
If the file is large, Why should you read once, whole the file into the memory?
You can read a little piece every time. The size is determined with the size in this func:
file.read(buff, size)
When the buff is char's array.
I'm sorry, but You can't simplest read/save vector to file.
for more details see here and here.
And use Google, It's very helpful...
You didn't give too much context of what you're trying to do in your question. But here's one quick & dirty way to do it:
#include <iterator>
#include <fstream>
#include <vector>
#include <assert.h>
using namespace std;
const char *filename = "foo.bar";
int main()
{
vector<bool> v;
ifstream binary_file(filename, ios::binary);
assert(binary_file);
copy(istream_iterator<unsigned char>(binary_file),
istream_iterator<unsigned char>(),
back_insert_iterator< vector<bool> >(v));
}
Reading the zero-byte '\0' character into the vector will be false. Any other bytes read in will be treated as true.
and thank you in advance for your help!
I am in the process of learning C++. My first project is to write a parser for a binary-file format we use at my lab. I was able to get a parser working fairly easily in Matlab using "fread", and it looks like that may work for what I am trying to do in C++. But from what I've read, it seems that using an ifstream is the recommended way.
My question is two-fold. First, what, exactly, are the advantages of using ifstream over fread?
Second, how can I use ifstream to solve my problem? Here's what I'm trying to do. I have a binary file containing a structured set of ints, floats, and 64-bit ints. There are 8 data fields all told, and I'd like to read each into its own array.
The structure of the data is as follows, in repeated 288-byte blocks:
Bytes 0-3: int
Bytes 4-7: int
Bytes 8-11: float
Bytes 12-15: float
Bytes 16-19: float
Bytes 20-23: float
Bytes 24-31: int64
Bytes 32-287: 64x float
I am able to read the file into memory as a char * array, with the fstream read command:
char * buffer;
ifstream datafile (filename,ios::in|ios::binary|ios::ate);
datafile.read (buffer, filesize); // Filesize in bytes
So, from what I understand, I now have a pointer to an array called "buffer". If I were to call buffer[0], I should get a 1-byte memory address, right? (Instead, I'm getting a seg fault.)
What I now need to do really ought to be very simple. After executing the above ifstream code, I should have a fairly long buffer populated with a number of 1's and 0's. I just want to be able to read this stuff from memory, 32-bits at a time, casting as integers or floats depending on which 4-byte block I'm currently working on.
For example, if the binary file contained N 288-byte blocks of data, each array I extract should have N members each. (With the exception of the last array, which will have 64N members.)
Since I have the binary data in memory, I basically just want to read from buffer, one 32-bit number at a time, and place the resulting value in the appropriate array.
Lastly - can I access multiple array positions at a time, a la Matlab? (e.g. array(3:5) -> [1,2,1] for array = [3,4,1,2,1])
Firstly, the advantage of using iostreams, and in particular file streams, relates to resource management. Automatic file stream variables will be closed and cleaned up when they go out of scope, rather than having to manually clean them up with fclose. This is important if other code in the same scope can throw exceptions.
Secondly, one possible way to address this type of problem is to simply define the stream insertion and extraction operators in an appropriate manner. In this case, because you have a composite type, you need to help the compiler by telling it not to add padding bytes inside the type. The following code should work on gcc and microsoft compilers.
#pragma pack(1)
struct MyData
{
int i0;
int i1;
float f0;
float f1;
float f2;
float f3;
uint64_t ui0;
float f4[64];
};
#pragma pop(1)
std::istream& operator>>( std::istream& is, MyData& data ) {
is.read( reinterpret_cast<char*>(&data), sizeof(data) );
return is;
}
std::ostream& operator<<( std::ostream& os, const MyData& data ) {
os.write( reinterpret_cast<const char*>(&data), sizeof(data) );
return os;
}
char * buffer;
ifstream datafile (filename,ios::in|ios::binary|ios::ate);
datafile.read (buffer, filesize); // Filesize in bytes
you need to allocate a buffer first before you read into it:
buffer = new filesize[filesize];
datafile.read (buffer, filesize);
as to the advantages of ifstream, well it is a matter of abstraction. You can abstract the contents of your file in a more convenient way. You then do not have to work with buffers but instead can create the structure using classes and then hide the details about how it is stored in the file by overloading the << operator for instance.
You might perhaps look for serialization libraries for C++. Perhaps s11n might be useful.
This question shows how you can convert data from a buffer to a certain type. In general, you should prefer using a std::vector<char> as your buffer. This would then look like this:
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
int main() {
std::ifstream input("your_file.dat");
std::vector<char> buffer;
std::copy(std::istreambuf_iterator<char>(input),
std::istreambuf_iterator<char>(),
std::back_inserter(buffer));
}
This code will read the entire file into your buffer. The next thing you'd want to do is to write your data into valarrays (for the selection you want). valarray is constant in size, so you have to be able to calculate the required size of your array up-front. This should do it for your format:
std::valarray array1(buffer.size()/288); // each entry takes up 288 bytes
Then you'd use a normal for-loop to insert the elements into your arrays:
for(int i = 0; i < buffer.size()/288; i++) {
array1[i] = *(reinterpret_cast<int *>(buffer[i*288])); // first position
array2[i] = *(reinterpret_cast<int *>(buffer[i*288]+4)); // second position
}
Note that on a 64-bit system this is unlikely to work as you expect, because an integer would take up 8 bytes there. This question explains a bit about C++ and sizes of types.
The selection you describe there can be achieved using valarray.