How do I access .HGT SRTM files in C++? - c++

Here is a similar question on the topic with a good description of the file:
how to read NASA .hgt binary files
I am fairly new to programming in general and my efforts thus far have been very limited. My ultimate goal is to access the elevation data and store it in a 2D array for easy access. I have been trying to read the file 2 bytes at a time, as has been suggested, but I don't know what to do next. Here is what I've got so far:
#include <iostream>
#include <fstream>
using namespace std;
int main ()
{
ifstream::pos_type size;
char * memblock;
ifstream file ("N34W119.hgt", ios::in|ios::binary|ios::ate);
if (file.is_open())
{
size = 2;
memblock = new char [size];
file.seekg (0, ios::beg);
file.read (memblock, size);
//I don't know what to do next
file.close();
}
return 0;
}
Thanks for any help!

// SRTM_version 1201 or 3601
int height[SRTM_version][SRTM_version];
for ( int r = 0; r < SRTM_version ; r++ ) {
for ( int c = 0 ; c < SRTM_verision; c++ ) {
height[r][c] = (memblock[0] << 8) | memblock[1];
}
}

Related

Read binary file and count specific number c++

Hey everyone I've been looking everywhere for insight on how to do this particular assignment. I saw something similar but it didn't have a clear explanation. I'm trying to read a bin file and count the number of times a specific number appears. I saw examples of this using a .txt file and it seemed very straight forward using getline. I tried to replicate the similar structure but using a binary file.
int main() {
int searching = 3;
int counter = 0;
unsigned char * memblock;
long long int size;
//open bin file
ifstream file;
file.open("threesData.bin", ios:: in | ios::binary | ios::ate);
//read bin file
if (file.is_open()) {
cout << "it opened\n";
size = file.tellg();
memblock = new unsigned char[size];
file.seekg(0, ios::beg);
file.read((char * ) memblock, size);
while (file.read((char * ) memblock, size)) {
for (int i = 0; i < size; i++) {
(int) memblock[i];
if (memblock[i] == searching) {
counter++;
}
}
}
}
file.close();
cout << "The number " << searching << " appears ";
cout << counter << " times!";
return 0;
}
When I run the program it's clear that it opens but it doesn't count the number I'm searching for. What am I doing wrong?
You seem to be thinking this through but here's how I would go about doing it.
Initialize a buffer with a sensible size.
Cast it to integers, so you can do array[size_t] syntax for simpler arithmetic.
Open the stream, and read while the stream is valid.
Convert the number of read bytes to the number of ints you would expect.
Increment the counter for each character you find that is valid.
Code
#include <fstream>
#include <iostream>
bool check_character(int value)
{
return value == 3;
}
int main(void)
{
// choose the size, cast a pointer as an int type, and initialize
// our counter
static constexpr size_t size = 4096;
char* buffer = new char[size];
int* ints = (int*) buffer;
size_t counter = 0;
// create our stream,
std::ifstream stream("file.bin", std::ios_base::binary);
while (stream) {
// keep reading while the stream is valid
stream.read(buffer, size);
auto count = stream.gcount();
// we only want to go to the last valid integer
// if we expect the file to be only integers,
// we could do `assert(count % sizeof(int) == 0);
// otherwise, we may have trailing characters
// if we have trailing characters, we may want to move them
// to the front of the buffer....
auto chars = count / sizeof(int); // floor division
for (size_t i = 0; i < chars; ++i) {
// false == 0, true == 1, so we can just add
// if the value is 3
counter += check_character(ints[i]);
}
}
std::cout << "Counter is: " << counter << std::endl;
delete[] buffer;
return 0;
}
As NeilButterworth points out, you could also use a vector. I don't really like this, but "meh".
#include <fstream>
#include <iostream>
#include <vector>
/* ellipsed lines */
int main(void)
{
/* ellipsed lines */
static constexpr size_t size = 4096;
std::vector<int> ints;
ints.resize(size / sizeof(int));
char* buffer = (char*) ints.data();
/* ellipsed lines */
/* ellipsed lines */
std::cout << "Counter is: " << counter << std::endl;
// no delete[]
return 0;
}

Why do I see the contents of binary files?

Why I can open and view binary files . odd appearance that is impossible ?
http://codepad.org/OwX99H0p
Enter a string str -> char arr1[] -> FILEOUT.DAT
FILEOUT.DAT -> char arr2[] -> Printed screens
The code in question:
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
void NhapMang(char *&arr, string str , int &n)
{
n = str.length();
arr = new char[n];
for (int i = 0; i < n;i++)
{
arr[i] = str[i];
}
}
void XuatMang(char *arr, int n)
{
for (int i = 0; i < n;i++)
{
cout << arr[i];
}
}
void GhiFile(ofstream &FileOut, char *arr, int n)
{
FileOut.open("OUTPUT.DAT", ios::out | ios::binary);
FileOut.write(arr, n*sizeof(char));
FileOut.close();
}
void DocFile(ifstream &FileInt, char *&arr, int n)
{
FileInt.open("OUTPUT.DAT", ios::in | ios::binary);
arr = new char[n];
FileInt.read(arr, n*sizeof(char));
FileInt.close();
}
int main()
{
char *arr1;
int n1;
fflush(stdin);
string str;
getline(cin, str);
NhapMang(arr1, str,n1);
ofstream FileOut;
GhiFile(FileOut, arr1, n1);
char *arr2;
int n2 = n1;
ifstream FileInt;
DocFile(FileInt, arr2, n2);
XuatMang(arr2, n2);
delete[] arr1;
delete[] arr2;
system("pause");
return 0;
}
You're ultimately storing data in a file. What this data represents is up to you, keep in mind, it's all '1's and '0's in the end. When you open the file you've created with a text editor, it will try to interpret this data as text which doesn't give a readable result.
Imagine storing a liquid in a bottle. If you don't label it, no one knows what it is. If you then pour this liquid in your car, it will try to use this as gasoline and potentially wreck your engine. Computers, fortunately, are much more forgiving.
Most files store information about how the data can be interpreted in their headers so programs can check if the file type is supported or not. So trying to open this file in a media player for example is most likely telling you that this format is not supported instead of trying to interpret the data as a media.

c++ seekp(0,ios::end) not working

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

Split a binary file into chunks c++

I've been bashing my head against trying to first divide up a file into chunks, for the purpose of sending over sockets. I can read / write a file easily without splitting it into chunks. The code below runs, works, kinda. It will write a textfile and has a garbage character. Which if this was just for txt, no problem. Jpegs aren't working with said garbage.
Been at it for a few days, so I've done my research, and it's time to get some help. I do want to stick strictly to binary readers, as this need to handle any file.
I've seen a lot of slick examples out there. (none of them worked for me with jpgs) Mostly something along the lines of while(file)... I subscribe to the, if you know the size, use a for-loop, not a while-loop camp.
Thank you for the help!!
vector<char*> readFile(const char* fn){
vector<char*> v;
ifstream::pos_type size;
char * memblock;
ifstream file;
file.open(fn,ios::in|ios::binary|ios::ate);
if (file.is_open()) {
size = fileS(fn);
file.seekg (0, ios::beg);
int bs = size/3; // arbitrary. Actual program will use the socket send size
int ws = 0;
int i = 0;
for(i = 0; i < size; i+=bs){
if(i+bs > size)
ws = size%bs;
else
ws = bs;
memblock = new char [ws];
file.read (memblock, ws);
v.push_back(memblock);
}
}
else{
exit(-4);
}
return v;
}
int main(int argc, char **argv) {
vector<char*> v = readFile("foo.txt");
ofstream myFile ("bar.txt", ios::out | ios::binary);
for(vector<char*>::iterator it = v.begin(); it!=v.end(); ++it ){
myFile.write(*it,strlen(*it));
}
}
The problem is that you are using a strlen to calculate the size of array to be written. A 0 to be a part of binary there you would not be writing the right size. Instead, use a pair of char*,int where int specifies the size that is to be written and you will be golden.
Like:
#include <iostream>
#include <vector>
#include <fstream>
#include <stdlib.h>
#include <string.h>
using namespace std;
ifstream::pos_type fileS(const char* fn)
{
ifstream file;
file.open(fn,ios::in|ios::binary);
file.seekg(0, ios::end);
ifstream::pos_type ret= file.tellg();
file.seekg(0,ios::beg);
ret=ret-file.tellg();
file.close();
return ret;
}
vector< pair<char*,int> > readFile(const char* fn){
vector< pair<char*,int> > v;
ifstream::pos_type size;
char * memblock;
ifstream file;
file.open(fn,ios::in|ios::binary|ios::ate);
if (file.is_open()) {
size = fileS(fn);
file.seekg (0, ios::beg);
int bs = size/3; // arbitrary. Actual program will use the socket send size
int ws = 0;
int i = 0;
cout<<"size:"<<size<<" bs:"<<bs<<endl;
for(i = 0; i < size; i+=bs){
if(i+bs > size)
ws = size%bs;
else
ws = bs;
cout<<"read:"<<ws<<endl;
memblock = new char [ws];
file.read (memblock, ws);
v.push_back(make_pair(memblock,ws));
}
}
else{
exit(-4);
}
return v;
}
int main(int argc, char **argv) {
vector< pair<char*,int> > v = readFile("a.png");
ofstream myFile ("out.png", ios::out | ios::binary);
for(vector< pair<char*,int> >::iterator it = v.begin(); it!=v.end(); ++it ){
pair<char*,int> p=*it;
myFile.write(p.first,p.second);
}
}
myFile.write(*it,strlen(*it));
Is using string length on binary data. I suspect that is your culprit. If not, it's certainly a code-smell.
You should never do this:
myFile.write(*it,strlen(*it));
on binary data. strlen counts bytes until it hits a byte which contains a 0 (NUL as we like to say, but it's an honest 0). If you read enough binary data, you will hit a NUL, and you'll get a short count. But actually the situation could be a lot worse, because nowhere do you store the NUL for strlen to find. You're just counting on there being one beyond the end of the datablock you acquire to read the file into.
So don't do that. Remember the number of bytes in each block (you could use a vector> but there are a lot of more C++-like possibilities) and use that to write the data.

How to output array of doubles to hard drive?

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.