1

I'm looking for some help piping a file (16-bit signed little endian integers raw data) from the command line to my program:

cat rawdata.dat | myprogram

The code works pretty well on Linux, 512 bytes are transformed into 256 ints per loop turn.

If I compile it with MinGW on Windows, only the first 76 values will be transformed correctly. Also the program stops after the first while loop.

Does anybody know what I am doing wrong? I am using Windows 7 64bit + MinGW compiler.

Code:

#include <iostream>

using namespace std;

int main() 
{
    int BUF_LEN = 512;
    char buf[BUF_LEN];

    while(!cin.eof()) 
    {
        cin.read(buf, BUF_LEN);
        int16_t* data = (int16_t*) buf; //to int

        for(int i=70;i<85;i++)
        {
            cout << i << "   " << data[i] << endl;
        }
    }
    return 0;
}

Testfile: http://www.filedropper.com/rawdata

Correct values would be:

70   -11584
71   13452
72   -13210
73   -13331
74   13893
75   10870
76   9738
77   6689
78   -253
79   -1009
80   -16036
81   14253
82   -13872
83   10020
84   -5971
fuxT
  • 63
  • 1
  • 5
  • 1
    Regarding `while(!cin.eof())`, [give this link a read](http://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong). – user4581301 Jul 24 '15 at 23:38
  • 1
    Note: in Windows, a binary 8-bit value of 0x1A (or 26 decimal) indicates end of file, unless you opened the file as "binary" (i.e. no translations). – Thomas Matthews Jul 25 '15 at 00:12
  • 1
    BTW, binary files are best opened directly rather than going through `cin`. Personally, I would never pipe a binary file into my program; too many things can go wrong. – Thomas Matthews Jul 25 '15 at 00:13

2 Answers2

0

TL;DR:

Fix? There isn't one. You have to force cin into binary mode. I think to do that you'd have to close and reopen cin, and I can only see that ending badly.

Real solution is don't do this. Open the file normally with

std::ifstream in("rawdata.dat", std::fstream::binary);

Rest of the story:

Suspected that this would be some sort of gooned binary translation, so I put together a quick bit of code to see what's going on in the file.

#include <iostream>
#include <fstream>

using namespace std;

#define BUF_LEN 512

int main()
{
    ifstream in("rawdata.dat");
    char buf[BUF_LEN];
    int16_t test;
    int count = 0;
    while(in.read((char *)&test, sizeof(test)))
    {
        cout << count++ << ":" << in.tellg() << ":" << test << endl;
        if (count == 85)
        {
            break;
        }
    }
    return 0;
}

Important output (int16 number:position in file:number read

0:358:0

First value returned is actually at position 358. Not sure why.

75:508:10870
76:510:9738
77:909:8225
78:911:11948

Wooo-eee! Look at that position jump from 510 to 909. Nasty. 510 would be right around the end of the buffer, but it doesn't look like the buffer is being respected.

My understanding is istream::read should be totally unformatted, just a dumb copy of input stream to provided buffer so I have no idea why this happens. Maybe windows is just weird.

Addendum

Thomas Matthews probably has the right idea, secret Windows control characters, but 510 is a rather innocuous comma. Why go bonkers over a comma?

user4581301
  • 29,019
  • 5
  • 26
  • 45
0

This one finally solved my problem:

Read binary data from std::cin

Just add the following lines to your code if you are using MinGW:

#include <io.h>
#include <fcntl.h>
#include <fstream>
_setmode(_fileno(stdin), _O_BINARY);
Community
  • 1
  • 1
fuxT
  • 63
  • 1
  • 5