6

I am trying to read a large binary file thought input redirection (stdin) at runtime, and stdin is mandatory.

./a.out < input.bin

So far I have used fgets. But fgets skips blanks and newline. I want to include both. My currentBuffersize could dynamically vary.

FILE * inputFileStream = stdin; 
int currentPos = INIT_BUFFER_SIZE;
int currentBufferSize = 24; // opt
unsigned short int count = 0; // As Max number of packets 30,000/65,536
while (!feof(inputFileStream)) {
    char buf[INIT_BUFFER_SIZE]; // size of byte
    fgets(buf, sizeof(buf), inputFileStream);
    cout<<buf;
    cout<<endl;
}

Thanks in advance.

jww
  • 97,681
  • 90
  • 411
  • 885
Jerry
  • 73
  • 1
  • 5
  • 3
    `fread` is for unprocessed input. `fgets` as you say does text processing. **Don't ignore the return value which is the number of valid records stored to the buffer.** – Ben Voigt Sep 28 '16 at 20:48
  • 2
    See "http://stackoverflow.com/questions/7587595/read-binary-data-from-stdcin" Duplicate? Answer there is you can't. – 2785528 Sep 28 '16 at 20:56
  • 1
    Why are you using C stdio in C++? – Barmar Sep 28 '16 at 21:03
  • @DOUGLASO.MOEN Yes you can. First of all, that question is specifically about doing it with `cin`, so it's not really related to this question, and secondly, the answer there actually tells you how to do it. *This* question was just a failure to read documentation for stdio / a failure to search Google for ["read binary data from stdin"](https://www.google.com/search?q=read+binary+data+from+stdin). – Jason C Sep 28 '16 at 21:04
  • @Barmar Probably because iostreams is a huge pain, and, more importantly, who cares. – Jason C Sep 28 '16 at 21:07
  • 2
    @JasonC ... thanks, I did not distinguish stdin from std::cin on first read. – 2785528 Sep 28 '16 at 21:08
  • @Jerry - Do you really intend to restrict to stdin? You marked this as C++. Except for cout, your code seems to be a C effort. And redirection of input to a C++ program goes to std::cin. – 2785528 Sep 28 '16 at 21:13
  • @DOUGLASO.MOEN - I am not restricted to stdin but our testcase file should be redirected at runtime... so is there a better way.. ? – Jerry Sep 28 '16 at 21:18
  • @BenVoigt I need the blank or empty values.. fread still removes those characters. could you tell whats the use of third argument... – Jerry Sep 28 '16 at 21:51
  • fread isn't removing them, check your display code – Ben Voigt Sep 28 '16 at 22:08

1 Answers1

13

If it were me I would probably do something similar to this:

const std::size_t INIT_BUFFER_SIZE = 1024;

int main()
{
    try
    {
        // on some systems you may need to reopen stdin in binary mode
        // this is supposed to be reasonably portable
        std::freopen(nullptr, "rb", stdin);

        if(std::ferror(stdin))
            throw std::runtime_error(std::strerror(errno));

        std::size_t len;
        std::array<char, INIT_BUFFER_SIZE> buf;

        // somewhere to store the data
        std::vector<char> input;

        // use std::fread and remember to only use as many bytes as are returned
        // according to len
        while((len = std::fread(buf.data(), sizeof(buf[0]), buf.size(), stdin)) > 0)
        {
            // whoopsie
            if(std::ferror(stdin) && !std::feof(stdin))
                throw std::runtime_error(std::strerror(errno));

            // use {buf.data(), buf.data() + len} here
            input.insert(input.end(), buf.data(), buf.data() + len); // append to vector
        }

        // use input vector here
    }
    catch(std::exception const& e)
    {
        std::cerr << e.what() << '\n';
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

Note you may need to re-open stdin in binary mode not sure how portable that is but various documentation suggests is reasonably well supported across systems.

Galik
  • 47,303
  • 4
  • 80
  • 117
  • I have recently started programming in C++ could you explain me this method fread(buf.data(), sizeof(buf[0]), buf.size(), stdin)) ... I understand the this function reads unprocessed filestream - stdin, but I am lost at the first three arguments... – Jerry Sep 28 '16 at 21:46
  • @Jerry Its probably worth reading through the documentation: http://en.cppreference.com/w/cpp/io/c/fread If you only care about reading bytes then just set the second argument to `1`, then the third argument says how many bytes to read. Sometimes people read chunks of bytes at a time so they set the second argument to the number of bytes in each record (chunk). In all cases the number of bytes to read is the multiplication of the sizes in the second and third arguments. – Galik Sep 28 '16 at 21:51
  • I used `sizeof(buf[0])` because, if I change my `std::array` to contain objects that are larger than `char` the parameters to `std::fread` will automatically adjust for that. – Galik Sep 28 '16 at 21:53
  • oh.. I got it..and fread is supposed to read blanks and newlines too isn't... but for some reason its skipping them.. – Jerry Sep 28 '16 at 22:09
  • @Jerry It shouldn't skip them esp if you `freopn` in binary mode as per my example. If it continues to skip them I suggest you edit your question posting a complete code example that produces the error you are describing. – Galik Sep 28 '16 at 22:11
  • its working with fwrite. can you tell me how to append the buffer content to arrary or string... If I try to print the buffer then the loop is not terminating and on force termination some current buffer value is printed... – Jerry Sep 30 '16 at 01:30
  • @Jerry I modified the example to append each received buffer of data to a `std::vector` called `input`. Basically each time round the loop the data that was read begins at `buf.data()` and ends at `buf.data() + len`. – Galik Sep 30 '16 at 01:41
  • Thanks a lot it works :) .. I have used char[] as I wasnt't able to figure out array buf; – Jerry Sep 30 '16 at 02:23