I am trying to write a basic binary VTK file to display some data using ParaView but I have some errors and I don't understand why. Here is my test code in C++:
#include <iostream>
#include <fstream>
double myarray[72] = {
0,0,0,1,0,0,2,0,0,3,0,0,4,0,0,
5,0,0,0,1,0,1,1,0,2,1,0,3,1,0,
4,1,0,5,1,0,0,2,0,1,2,0,2,2,0,
3,2,0,4,2,0,5,2,0,0,3,0,1,3,0,
2,3,0,3,3,0,4,3,0,5,3,0};
int main()
{
std::ofstream vtkstream("test01.vtk", std::ios::out | std::ios::trunc);
bool ascii = false;
if (vtkstream) {
vtkstream<<"# vtk DataFile Version 2.0"<<"\n";
vtkstream<<"Exemple"<<"\n";
if (ascii) {
vtkstream<<"ASCII"<<"\n";
vtkstream.close();
vtkstream.clear();
vtkstream.open("test01.vtk", std::ios::out | std::ios::app);
vtkstream<<"DATASET STRUCTURED_GRID"<<std::endl;
vtkstream<<"DIMENSIONS 6 4 1"<<std::endl;
vtkstream<<"POINTS 24 double"<<std::endl;
for (unsigned int i = 0; i < 72; ++i) {
vtkstream<<myarray[i]<<" ";
}
} else {
vtkstream<<"BINARY"<<"\n";
vtkstream.close();
vtkstream.clear();
vtkstream.open("test01.vtk", std::ios::out | std::ios::app | std::ios::binary);
vtkstream<<"DATASET STRUCTURED_GRID"<<std::endl;
vtkstream<<"DIMENSIONS 6 4 1"<<std::endl;
vtkstream<<"POINTS 24 double"<<std::endl;
for (unsigned int i = 0; i < 72; ++i) {
vtkstream<<myarray[i];
}
}
vtkstream.close();
} else {
std::cout<<"ERROR"<<std::endl;
}
return 0;
}
The ASCII file format works perfectly but the binary version produces the following error in ParaView:
Generic Warning: In ........\src\VTK\IO\vtkDataReader.cxx, line
1363 Error reading binary data!
Where is my mistake in the VTK format?
It seems that VTK assumes that binary files are written as big endian, whereas most PCs use little endian storage (see the bottom of page 2 of the VTK file formats document). Can you try swapping the byte order when writing binary data and see if this solves your problem?
See also this VTK users post, which is similar to this question.
My 50 cents. Here is the code that finally worked for me. Using byte swap, and using the function write to skip the formatting of the << operator
#include <iostream>
#include <fstream>
// Thanks to https://stackoverflow.com/questions/105252
template <typename T>
void SwapEnd(T& var)
{
char* varArray = reinterpret_cast<char*>(&var);
for(long i = 0; i < static_cast<long>(sizeof(var)/2); i++)
std::swap(varArray[sizeof(var) - 1 - i],varArray[i]);
}
double myarray[72] = {
0.001,0.002,0,1,0,0,2,0,0,3,0,0,4,0,0,
5,0,0,0,1,0,1,1,0,2,1,0,3,1,0,
4,1,0,5,1,0,0,2,0,1,2,0,2,2,0,
3,2,0,4,2,0,5,2,0,0,3,0,1,3,0,
2,3,0,3,3,0,4,3,0,5,3,0};
int main()
{
std::ofstream vtkstream;
vtkstream.open("test.vtk", std::ios::out | std::ios::app | std::ios::binary);
if (vtkstream) {
vtkstream<<"# vtk DataFile Version 2.0"<<"\n";
vtkstream<<"Exemple"<<"\n";
vtkstream<<"BINARY"<<"\n";
vtkstream<<"DATASET STRUCTURED_GRID"<<std::endl;
vtkstream<<"DIMENSIONS 6 4 1"<<std::endl;
vtkstream<<"POINTS 24 double"<<std::endl;
for (unsigned int i = 0; i < 72; ++i) {
SwapEnd(myarray[i]);
vtkstream.write((char*)&myarray[i], sizeof(double));
}
vtkstream.close();
} else {
std::cout<<"ERROR"<<std::endl;
}
return 0;
}
Related
I am trying to open a binary file, read from it and then open multiple files with std::ofstreamand write into seperate files randomly. However, i get some garbage values in the written binary file. Is it not possible to write into multiple files paralel? What could be the cause of this issue?
Because when i create one ofstream and write everything, it seems okay. Here is my code for writing to binary:
//For reading from a binary file
std::ifstream fileInput;
fileInput.exceptions(std::ifstream::failbit | std::ifstream::badbit);
const int numberOfFiles = 5;
std::ofstream outfile[numberOfFiles];
std::stringstream sstm;
for (int i = 0; i < numberOfFiles; i++)
{
sstm.str("");
sstm << "test" << i;
outfile[i].open(sstm.str());
}
try
{
fileInput.open("TestBinary.dat", std::ios::binary);
float f;
int newLineCounter = 0;
int index = 0;
while (fileInput.read(reinterpret_cast<char*>(&f), sizeof(float)))
{
outfile[index].write(reinterpret_cast<const char*>(&f), sizeof(float));
newLineCounter++;
// Since i am reading 3D points
if (newLineCounter == 3)
{
index = rand() % numberOfFiles;
newLineCounter = 0;
}
}
for (int i = 0; i < numberOfFiles; i++)
{
outfile[i].close();
}
fileInput.close();
}
catch (std::ifstream::failure e) {
std::cerr << "Exception opening/reading/closing file\n";
}
when i read the file i get garbage values like this:
979383418452721018666090051403776.000000 500207915157676809436722056201764864.000000 2.16899e+17
You're opening your files in text mode. You need to open them in binary mode.
outfile[i].open(sstm.str(), ios_base::out | ios_base::binary);
Hi I'm trying to read string from txt file and transform it into binary file which is bitset<12> string form.
int main()
{
using namespace std;
std::ifstream f("fruit.txt");
std::ofstream out("result.txt");
std::hash<std::string>hash_fn;
int words_in_file = 0;
std::string str;
while (f >> str){
++words_in_file;
std::bitset<12>* bin_str = new std::bitset<12>[3000];
int temp_hash[sizeof(f)];
std::size_t str_hash = hash_fn(str);
temp_hash[words_in_file] = (unsigned int)str_hash;
bin_str[words_in_file] = std::bitset<12>((unsigned int)temp_hash[words_in_file]);
out << bin_str[words_in_file] << endl;
delete[] bin_str;
}
out.close();
}
but there is error. How can I change it?
Here is some code that I wrote that turns the input file "file.txt" into binary. It does this by taking the ascii value of each character and representing that number as a binary value, although I'm not sure how to write bin_str to a file here.
#include <string>
#include <fstream>
#include <streambuf>
#include <bitset>
#include <iostream>
int main(){
std::ifstream f("file.txt");
std::string str((std::istreambuf_iterator<char>(f)),
std::istreambuf_iterator<char>()); // Load the file into the string
std::bitset<12> bin_str[str.size()]; // Create an array of std::bitset that is the size of the string
for (int i = 0; i < str.size(); i++) {
bin_str[i] = std::bitset<12>((int) str[i]); // load the array
std::cout << bin_str[i] << std::endl; // print for checking
}
}
SIDE NOTE:
std::bitset<12> may not be what you want, if you look at ascii characters the highest number you can have is 127 and in binary that's only 7 digits so I'd assume you'd want something more like std::bitset<7> or std::bitset<8>
EDIT:
If you want to write it to a file you'll need to open a file with std::ios::binary and then loop through the array of bitsets and write their unsigned long representative, given from to_ulong(), as a const char pointer ((const char*)&ulong_bin). Now when you open the file with a binary editor you will see the difference between the binary write and the regular write, but you'll notice that programs like cat can still decipher the binary you've written as simple ascii letters.
std::ofstream out("file.bin", std::ios::binary);
for (int i = 0; i < str.size(); i++) {
unsigned long ulong_bin = bin_str[i].to_ulong();
out.write((const char*)&ulong_bin, sizeof(ulong_bin));
}
EDIT: Credit to #PeterT
It has come to my attention that VLAs, variable length arrays, are not supported in C++11 and up so the line std::bitset<12> bin_str[str.size()]; should be changed to one of the following:
std::bitset<12> *bin_str = new std::bitset<12>[str.size()]; // make sure you delete it later
// OR
std::vector<std::bitset<12>> bin_str(str.size());
// OR
std::unique_ptr<std::bitset<12>[]> str_ptr (new std::bitset<12>[str.size()]);
Apologize for my poor English.
I am stuck by fstream in C++. Here is my code.
#include<iostream>
#include<fstream>
using namespace std;
struct TestStruct
{
int a;
char str[30];
TestStruct(int a_, const char* s)
{
a = a_;
strcpy_s(str,sizeof(char)*30, s);
}
TestStruct() = default;
};
int main()
{
fstream output("out.bin", ios::out|ios::binary);
output.seekp(0,ios::end);
cout << output.tellp() << endl;
for (int i = 0; i < 15; i++) {
TestStruct a(10*i, "asdadas");
output.write(reinterpret_cast<char*>(&a), sizeof(a));
}
output.close();
fstream input("out.bin", ios::in | ios::binary);
input.seekg(2 * sizeof(TestStruct), ios::beg);
for (int i = 0; i < 5; i++) {
TestStruct a;
input.read(reinterpret_cast<char*>(&a), sizeof(a));
cout <<"file_pointer"<<input.tellg()<<'\t'<<a.a << endl;
}
}
I use seekp(0,ios::end) to add new entry in the file. So the file should get lager when I run this code. But actually the file haven't change at all.
Here is the output:
> 0 <--tellp() always return 0
> file_pointer108 20
> file_pointer144 30
> file_pointer180 40
> file_pointer216 50
> file_pointer252 60
Add ios::app to the output's flags. You won't need to do output.seekp(0, ios::end); then.
While it may not seem like it seekp(0, ios::end) is actually working.
The reason it returns 0 is because you accidentally create a new empty file.
And the end cursor position of a new empty file is 0.
It creates a new file because of the file mode you use:
output("out.bin", ios::out|ios::binary);
https://en.cppreference.com/w/cpp/io/basic_filebuf/open
I need to read a file in as binary data, making sure the file is an even number of 32 bit words (I can add padding bytes of 0s if I need).
I've fiddled around with ios::binary but is there something I'm missing? For instance:
string name1 = "first", name2 = "sec", name3 = "third";
int j = 0, k = 0;
ifstream ifs(name1.c_str());
ifs >> j;
ifs.close();
Is this something I need to utilize? I'm fairly new to the language.
std::ifstream ifs(name1.c_str(), std::ifstream::binary);
if (!ifs)
{
// error opening file
}
else
{
int32_t j;
do
{
j = 0;
ifs.read(&j, sizeof(j));
if (ifs)
{
// read OK, use j as needed
}
else
{
if (ifs.eof())
{
// EOF reached, use j padded as needed
}
else
{
// error reading from file
}
break;
}
}
while (true);
ifs.close();
}
I was able to read 32bits using a similar method as Remy Lebeau. This code is compatible with C++03.
#include <stdint.h>
#include <fstream>
// Rest of code...
std::ifstream file(fileName, std::ifstream::in | std::ifstream::binary | std::ifstream::beg);
int32_t word;
if(!file){
//error
} else {
while(file.is_open()){
if(file.eof()){ printf("END\n"); break; }
word = 0;
file.read((char*)&word,sizeof(word));
//Do something
printf("%d\n",word);
}
}
Note that I do not add padding if the file is not in exact increments of 32. I'll update the code if I add that functionality.
I would like to know how to output an array of doubles to the hard drive.
edit:
for further clarification. I would like to output it to a file on the hard drive (I/O functions). Preferably in a file format that can be quickly translated back into an array of doubles in another program. It would also be nice if it was stored in a standard 4 byte configuration so that i can look at it through a hex viewer and see the actual values.
Hey... so you want to do it in a single write/read, well its not too hard, the following code should work fine, maybe need some extra error checking but the trial case was successful:
#include <string>
#include <fstream>
#include <iostream>
bool saveArray( const double* pdata, size_t length, const std::string& file_path )
{
std::ofstream os(file_path.c_str(), std::ios::binary | std::ios::out);
if ( !os.is_open() )
return false;
os.write(reinterpret_cast<const char*>(pdata), std::streamsize(length*sizeof(double)));
os.close();
return true;
}
bool loadArray( double* pdata, size_t length, const std::string& file_path)
{
std::ifstream is(file_path.c_str(), std::ios::binary | std::ios::in);
if ( !is.is_open() )
return false;
is.read(reinterpret_cast<char*>(pdata), std::streamsize(length*sizeof(double)));
is.close();
return true;
}
int main()
{
double* pDbl = new double[1000];
int i;
for (i=0 ; i<1000 ; i++)
pDbl[i] = double(rand());
saveArray(pDbl,1000,"test.txt");
double* pDblFromFile = new double[1000];
loadArray(pDblFromFile, 1000, "test.txt");
for (i=0 ; i<1000 ; i++)
{
if ( pDbl[i] != pDblFromFile[i] )
{
std::cout << "error, loaded data not the same!\n";
break;
}
}
if ( i==1000 )
std::cout << "success!\n";
delete [] pDbl;
delete [] pDblFromFile;
return 0;
}
Just make sure you allocate appropriate buffers! But thats a whole nother topic.
Use std::copy() with the stream iterators. This way if you change 'data' into another type the alterations to code would be trivial.
#include <algorithm>
#include <iterator>
#include <fstream>
int main()
{
double data[1000] = {/*Init Array */};
{
// Write data too a file.
std::ofstream outfile("data");
std::copy(data,
data+1000,
std::ostream_iterator<double>(outfile," ")
);
}
{
// Read data from a file
std::ifstream infile("data");
std::copy(std::istream_iterator<double>(infile),
std::istream_iterator<double>(),
data // Assuming data is large enough.
);
}
}
You can use iostream .read() and .write().
It works (very roughly!) like this:
double d[2048];
fill(d, d+2048, 0);
ofstream outfile ("save.bin", ios::binary);
outfile.write(reinterpret_cast<char*>(&d), sizeof(d));
ifstream infile ("save.bin", ios::binary);
infile.read(reinterpret_cast<char*>(&d), sizeof(d));
Note that this is not portable between CPU architectures. Some may have different sizes of double. Some may store the bytes in a different order. It shouldn't be used for data files that move between machines or data that is sent over the network.
#include <fstream.h>
void saveArray(double* array, int length);
int main()
{
double array[] = { 15.25, 15.2516, 84.168, 84356};
saveArray(array, 4);
return 0;
}
void saveArray(double* array, int length)
{
ofstream output("output.txt");
for(int i=0;i<length;i++)
{
output<<array[i]<<endl;
}
}
here is a way to output an array of doubles to text file one per line. hope this helps
EDIT
Change top one line to this two, and it will compile in VS. You can use multithreading to not blocking system wile saving data
#include <fstream>
using namespace std;
Now I feel old. I asked this question a long time ago (except about ints).
comp.lang.c++ link
#include <iostream>
#include <fstream>
using namespace std;
int main () {
double [] theArray=...;
int arrayLength=...;
ofstream myfile;
myfile.open ("example.txt");
for(int i=0; i<arrayLength; i++) {
myfile << theArray[i]<<"\n";
}
myfile.close();
return 0;
}
adapted from http://www.cplusplus.com/doc/tutorial/files/
Just set theArray and arrayLength to whatever your code requires.