I have a .dat file with ASCII characters like following picture:
It is basically a series of 16-bit numbers. I can read it, as unsigned short, in my data structure, but I have no idea how to save my unsigned short as same format as the input. Here is my current code, although the value is right, the format is not. See following picture:
Anyone has any idea how I should save it same as the input format? Here is my saving function"
void SavePxlShort(vector<Point3D> &pts, char * fileName)
{
ofstream os(fileName, ios::out);
size_t L = pts.size();
cout << "writing data (pixel as short) with length "<< L << " ......" << endl;
unsigned short pxl;
for (long i = 0; i < L; i++)
{
pxl = Round(pts[i].val());
if (pts[i].val() < USHRT_MAX)
{
os << pxl << endl;
}
else
{
cout << "pixel intensity overflow ushort" << endl;
return;
}
}
os.close();
return;
}
void SavePxlShort(vector<Point3D> &pts, char * fileName)
{
ofstream os(fileName, ios::out, ios::binary);
size_t L = pts.size();
cout << "writing data (pixel as short) with length "<< L << " ......" << endl;
unsigned short* pData = new unsigned short[L];
unsigned short pxl;
for (long i = 0; i < L; i++)
{
pxl = pts[i].val();
if (pts[i].val() < USHRT_MAX)
{
pData[i] = pxl ;
}
else
{
cout << "pixel intensity overflow ushort" << endl;
return;
}
}
os.write(reinterpret_cast<char*> (pData), sizeof(unsigned short)*L);
os.close();
delete pData;
return;
}
Two things:
You are are not opening the stream in binary mode. Try this:
ofstream os(fileName, ios::out | ios::binary);
Actually, because ofstream automatically sets the ios::out flag, you just need this:
ofstream os(fileName, ios::binary);
Another problem is that you are calling std::endl. This outputs a \n and then flushes the stream.
os << pxl << endl;
Change the above to just:
os << pxl;
in place of
os << pxl << endl;
You could put
os.write((char*)&pxl, sizeof(pxl));
to write the raw bytes of pxl into the file instead of the ASCII representation. Bear in mind the byte order and word size of an unsigned short may vary between systems.
Related
I'm reading blocks of data from the file, but not all at once (ex. 3 bytes per read/write) and then write same 3 bytes back to file to the very same position inside a file, and then continue looping until there are no more blocks to read.
In other words I'm trying to rewrite the file by it's very contents.
However there is a problem that final output isn't the same as it was in the beginning.
Following sample code reads 3 bytes per iteration from a file "sample.txt", file contents are simple:
0123456789
after reading data and writing data back to file, the contents are:
012345345345
As you see data doesn't get rewritten correctly for some reason.
#include <fstream>
#include <iostream>
using namespace std;
#define BLOCK_SIZE 3
int main()
{
// open file
fstream file;
file.open("sample.txt", ios::binary | ios::out | ios::in);
// determine size and number of blocks to read
file.seekg(0, ios::end);
streampos size = file.tellg();
int blocks = size / BLOCK_SIZE;
cout << "size:\t" << size << endl;
if (size % BLOCK_SIZE != 0)
{
++blocks;
}
cout << "blocks:\t" << blocks << endl;
// return to beginning
file.seekg(ios::beg);
// we will read data here
unsigned char* data = new unsigned char[BLOCK_SIZE];
streampos pos;
// read blocks of data and write data back
for (int i = 0; i < blocks; ++i)
{
pos = file.tellg();
cout << "before read:\t" << pos << endl;
// read block
file.read(reinterpret_cast<char*>(data), BLOCK_SIZE);
cout << "after read:\t" << file.tellg() << endl;
// write same block back to same position
file.seekp(pos);
cout << "before write:\t" << file.tellg() << endl;
file.write(reinterpret_cast<char*>(data), BLOCK_SIZE);
cout << "after write:\t" << file.tellg() << endl;
// reset buffer
memset(data, 0, BLOCK_SIZE);
}
file.close();
delete[] data;
cin.get();
return 0;
}
Do you see what could be the reason for bad overwrite?
EDIT:
Sorry, I can't see how the linked duplicate answers my question, I'm simply unable to apply given answer to the code above.
Your code does not handle the EOF condition well, and leaves the stream in a bad state after trying to read past the end of the file. On my system, this results in all further calls to the stream having no effect. I bet that isn't the case on your system (which I suspect is a bug in its iostream implementation). I re-did your code to handle the EOF condition correctly, and also to be a lot cleaner in a few other ways:
#include <fstream>
#include <iostream>
using namespace std;
const int BLOCK_SIZE = 3;
int main()
{
// open file
fstream file;
file.open("sample.txt", ios::binary | ios::out | ios::in);
// we will read data here
bool found_eof = false;
// read blocks of data and write data back
while (!found_eof)
{
unsigned char data[BLOCK_SIZE] = {0};
char * const data_as_char = reinterpret_cast<char *>(data);
streampos const pos = file.tellp();
int count_to_write = BLOCK_SIZE;
cout << "before read:\t" << file.tellg() << ' ' << pos << '\n';
// read block
if (!file.read(data_as_char, BLOCK_SIZE)) {
found_eof = true;
count_to_write = file.gcount();
file.clear();
cout << "Only " << count_to_write << " characters extracted.\n";
}
cout << "after read:\t" << file.tellg() << ' ' << file.tellp() << '\n';
// write same block back to same position
file.seekp(pos);
cout << "before write:\t" << file.tellg() << ' ' << file.tellp() << '\n';
file.write(data_as_char, count_to_write);
cout << "after write:\t" << file.tellg() << ' ' << file.tellp() << '\n';
file.seekp(file.tellp());
}
file.close();
cin.get();
return 0;
}
But, this is not fundamentally different. Both versions work for me just the same. I'm on Linux with g++.
From the linked to possible dupe, I would also suggest adding this just before the closing } of your for loop:
file.seekp(file.tellp());
I've put that in my code in the appropriate place.
I'm working on a project that involves binary files.
So I started researching about binary files but I'm still confused about how to write and fill a vector from that binary file that I wrote before
Here's code: for writing.
void binario(){
ofstream fout("./Binario/Data.AFe", ios::out | ios::binary);
vector<int> enteros;
enteros.push_back(1);
enteros.push_back(2);
enteros.push_back(3);
enteros.push_back(4);
enteros.push_back(5);
//fout.open()
//if (fout.is_open()) {
std::cout << "Entre al if" << '\n';
//while (!fout.eof()) {
std::cout << "Entre al while" << '\n';
std::cout << "Enteros size: "<< enteros.size() << '\n';
int size1 = enteros.size();
for (int i = 0; i < enteros.size(); i++) {
std::cout << "for " << i << '\n';
fout.write((char*)&size1, 4);
fout.write((char*)&enteros[i], size1 * sizeof(enteros));
//cout<< fout.get(entero[i])<<endl;
}
//fout.close();
//}
fout.close();
cout<<"copiado con exito"<<endl;
//}
}
Here's code for reading:
oid leerBinario(){
vector<int> list2;
ifstream is("./Binario/Data.AFe", ios::binary);
int size2;
is.read((char*)&size2, 4);
list2.resize(size2);
is.read((char*)&list2[0], size2 * sizeof(list2));
std::cout << "Size del vector: " << list2.size() <<endl;
for (int i = 0; i < list2.size(); i++) {
std::cout << i << ". " << list2[i] << '\n';
}
std::cout << "Antes de cerrar" << '\n';
is.close();
}
I don't know if I'm writing correctly to the file, this is just a test so I don't mess up my main file, instead of writing numbers I need to save Objects that are stored in a vector and load them everytime the user runs the program.
Nope, you're a bit confused. You're writing the size in every iteration, and then you're doing something completely undefined when you try to write the value. You can actually do this without the loop, when you are using a vector.
fout.write(&size1, sizeof(size1));
fout.write(enteros.data(), size1 * sizeof(int));
And reading in:
is.read(&list2[0], size2 * sizeof(int));
To be more portable you might want to use data types that won't change (for example when you switch from 32-bit compilation to 64-bit). In that case, use stuff from <cctype> -- e.g. int32_t for both the size and value data.
Consider the code:
const int length = 1024 * 1024; // 1048576
char buffer[length];
fstream f;
int main(int argc, char *argv[])
{
f.open("file.bin", ios::in | ios::out | ios::binary);
f.read(buffer, length);
int k = 0;
while (f.gcount() > 0)
{
k++;
cout << "Block #" << k << ": " << f.gcount() << " bytes" << endl;
f.read(buffer, f.gcount());
} // while
f.close();
return 0;
} // main
The size of the file "file.bin" is 2,895,872 bytes.
When I ran this code, the output is:
Block #1: 1048576 bytes
Block #2: 1048576 bytes
Block #3: 798720 bytes
Now, suppose that I want to do a useless thing: read each block and then write it again in the same file (in pratical terms this is a do nothing operation)
const int length = 1024 * 1024; // 1048576
char buffer[length];
fstream f;
int main(int argc, char *argv[])
{
f.open("file.bin", ios::in | ios::out | ios::binary);
f.read(buffer, length);
int k = 0;
while (f.gcount() > 0)
{
k++;
cout << "Block #" << k << ": " << f.gcount() << " bytes" << endl;
// this is the code I added
f.seekp(-f.gcount(), ios_base::cur); // move file pointer backwards
f.write(buffer, f.gcount()); // write the buffer again <=> do nothing
// end of the code I added
f.read(buffer, f.gcount());
} // while
f.close();
return 0;
} // main
Now the output is
Block #1: 1048576 bytes
Why Block #2 and #3 are not listed?
Thank you
The function seekp seeks on the output sequence, but the output sequence didn't change due to the fact that you were just reading (which changes the input sequence).
I think the best thing to do update the output sequence each time you perform a read, I'm not sure if it will work but you might try:
// ...
f.read(buffer, length);
f.seekp(f.gcount(), ios_base::cur); // update output sequence
int k = 0;
while (f.gcount() > 0)
{
k++;
cout << "Block #" << k << ": " << f.gcount() << " bytes" << endl;
// this is the code I added
f.seekp(-f.gcount(), ios_base::cur); // move file pointer backwards
f.write(buffer, f.gcount()); // write the buffer again <=> do nothing
// end of the code I added
f.read(buffer, f.gcount());
f.seekp(f.gcount(), ios_base::cur); // update output sequence
}
// ...
I am writing images to a binary file using this code:
std::ofstream edgefile("C:\\****\\edge.bin", std::ofstream::binary | std::ofstream::app | std::ofstream::out);
Mat edges;
Canny(bilat, edges, cthr1, cthr2, 3); //cany sliders
if (writeedge){
int rows = edges.rows;
int cols = edges.cols;
edgefile.write(reinterpret_cast<const char *>(&rows), sizeof(int));
edgefile.write(reinterpret_cast<const char *>(&cols), sizeof(int));
edgefile.write(reinterpret_cast<char*>(edges.data), edges.rows*edges.cols*sizeof(uchar));
cout << "writen r:" << rows << "C: " << cols << "Bytes: " << edges.rows*edges.cols*sizeof(uchar) << endl;
}
And then reading the same images with this:
std::ifstream infile;
int main(int argc, char* argv[])
{
int * ptr;
ptr = new int;
int rows;
int cols;
infile.open("C:\\****\\edge.bin", std::ofstream::binary | std::ofstream::app | std::ofstream::in);
while (!infile.eof())
{
infile.read(reinterpret_cast<char*>(ptr), sizeof(int));
rows = *ptr;
infile.read(reinterpret_cast<char*>(ptr), sizeof(int));
cols = *ptr;
Mat ed(rows, cols, CV_8UC1, Scalar::all(0));
infile.read(reinterpret_cast<char*>(ed.data), rows * cols * (sizeof uchar));
cout << "writen r: " << rows << " C: " << cols << " Bytes: " << rows * cols * (sizeof uchar) << endl;
imshow("God Knows", ed);
cvWaitKey();
}
infile.close();
return 0;
}
The images are read accurately however eof bit is not triggered at the end thus multiplying the last ptr value and reading another blank image at the end. After this the cycle ends. How can I check if the next bit is EOF bit without resetting the currently read position?
(I know that if 1 more byte would be read it would trigger the EOF bit)
The EOF bit is set after you try to read past the end of the file, that's just how streams work.
You can easily restructure the main loop to check the status after the first read. This works because the return value from read is a reference to the stream, and casting the reference to bool checks whether the stream is still in a good status (i.e. no EOF).
while (infile.read(reinterpret_cast<char*>(ptr), sizeof(int)))
{
// ...
The example code I've seen for this seems to use standard C file output functions, but I'd like to make it in C++.
I tried using fsteam functions to do it, but no data is written to the .bmp file at all.
So far, I have tried the standard <<, put, and write, and none of these work. If I open it up with a hex editor, the file is still empty.
It's odd, since the input functions work fine.
Here's a piece of the code I used to test to see if it was working:
output.open("WHITE.bmp");
output.put('B'); // this doesn't seem to work, the file is empty when I open it in a hex editor.
output.put('M');
And the rest of the code:
#include <iostream>
#include <fstream>
using namespace std;
typedef unsigned char byte;
typedef unsigned short dbyte;
struct BMPINFO
{
int width;
int height;
};
int main()
{
ifstream sourcefile;
ofstream output;
int threshold = 150;
sourcefile.open("RED.bmp");
if(sourcefile.fail())
{
cout << "Could not open RED.bmp" << endl;
return 1;
}
if(sourcefile.get() == 'B')
{
if(sourcefile.get() == 'M')
{
cout << "RED.bmp is a valid .bmp file" << endl;
}
}
else
{
cout << "RED.bmp is not a valid .bmp file" << endl;
return 1;
}
BMPINFO image;
// seeks to bitmap width, this file is little end in.
sourcefile.seekg (0x12, ios::beg);
unsigned int i = (unsigned)sourcefile.get();
i += (unsigned)sourcefile.get() << 8;
image.width = i;
cout << "The width of the image is: " << image.width << endl;
sourcefile.seekg (0x16, ios::beg);
i = sourcefile.get();
i += (unsigned)sourcefile.get() << 8;
image.height = i;
cout << "The height of the image is: " << image.height << endl;
int loc_pixels;
sourcefile.seekg (0x0A, ios::beg);
loc_pixels = sourcefile.get();
cout << "Location of pixel array is: " << loc_pixels << endl;
output.open("WHITE.bmp");
output.put('B'); // this doesn't seem to work, the file is empty when I open it in a hex editor.
output.put('M');
if(output.bad())
{
cout << "the attempt to output didn't work" << endl;
return 1;
}
sourcefile.seekg(loc_pixels, ios::beg);
char data[30000];
output.close();
return 0;
}
Is there a special function I should be using to output to this .bmp file?
EDIT - added more code, though most of it doesn't have to do with file output
You have a buffer overflow bug in this code:
char data[30000]; // Prepare file for usage -- just copy one thing from the file to the other
sourcefile.read(data, image.height * image.width );
You are reading in image.height*image.width bytes, and trying to fit them into 30000 bytes. You should structure your code so that those two numbers are related.
Try this:
std::vector<char> data(image.height * image.width);
sourcefile.read(&data[0], data.size());
There's a great description here.
ofstream myfile;
myfile.open("WHITE.bmp", ios::out | ios::binary); // opening in binary mode
myfile << 'B';
myfile << 'M';
myfile.close();