Question

Right now I am using istream to read in data. I have both text which I would like to read in as strings and numbers, and hashes which are read into character arrays. Since hashes are effectively random, I am hitting snags when I try to read it back in and hit EOF (which is part of the hash). Is there a way to accomplish this without resorting to fread. Also, is there a to use both istream and fread some I don't have to parse the integers and strings by hand. Finally, what is the best way to use fgets to get a string of unknown length.

Thanks, Eric

EDIT: Here is the code:

string dummy;
ifstream in(fileName);
for(int i=0; i<numVals; i++)
{
    int hashLen;
    in>>hashLen;
    char cc;
    in.get(cc);//Get the space in between
    cout<<"Got first byte: "<<(int)cc<<endl;

    char * hashChars = new char[hashLen];
    in.read(hashChars, hashLen);
    for(int j =0; j <hashLen; j++)
    {
        char c = hashChars[j];
       unsigned char cc = reinterpret_cast<unsigned char&>(c);
        cout<<"Got byte: "<<(int)c<<(int)cc<<endl;
        if(in.fail())
        {
            cout<<"Failed! "<<in.eof()<<" "<<in.bad()<<endl;
        }
    }

delete hashChars;

    getline(in,dummy);//get a dummy line
    cout<<"Dummy: "<<dummy<<" numvals: "<<numVals<<" i: "<<i<<" hashLength: "<<hashLen<<endl;
}

My output looks like:

1>Got first byte: 32

1>Got byte: 4 4

1>Got byte: -14 242

1>Got byte: 108 108

1>Got byte: 87 87

1>Got byte: 113 113

1>Got byte: -116 140

1>Got byte: -106 150

1>Got byte: -35 221

1>Got byte: 0 0

1>Got byte: -91 165

1>Got byte: 39 39

1>Got byte: 111 111

1>Got byte: 7 7

1>Got byte: 126 126

1>Got byte: 16 16

1>Got byte: -42 214

1>Dummy: numvals: 35 i: 12 hashLength: 16

1>Got first byte: 32

1>Got byte: 14 14

1>Failed! 1 0

1>Got byte: -65 191

1>Failed! 1 0

1>Got byte: -107 149

1>Failed! 1 0

1>Got byte: -44 212

1>Failed! 1 0

1>Got byte: -60 196

1>Failed! 1 0

1>Got byte: -51 205

1>Failed! 1 0

1>Got byte: -51 205

1>Failed! 1 0

Was it helpful?

Solution

When reading binary data you generally want to open your std::ifstream with the flag std::ios_base::binary. The resulting differences are fairly small but they generally do matter.

There are a few oddities in your code you might want to fix:

  • You always need to check after reading if the operation was successful, e.g., using if (in.read(hashChars, hashLen)) { ... }
  • There is no need to use reinterpret_cast<...>() which always has implementation defined semantics. You should use static_cast<unsigned char>(c) instead.
  • You allocate an array of characters but you release it using delete p. You need to use delete[] p instead. Using delete p results in undefined behavior. There isn't really any need to use new and delete at all, though, as std::vector<char> hashChars(hashLen) does automatic memory management.

There are a few [mutilated] questions otherwise embedded in the request above (so the questions/answers are guesses of what is being asked):

  • Can you mix std::istream::read() and fread() on the same stream (I suppose this is the question): not immediately unless the stream happens to be std::cin which reads from the same source as stdin. If you want to use both std::istream::read() and fread() on the same file you'll need to wrap a FILE* by a suitable std::streambuf and initialize an std::istream with the corresponding object.
  • How to read an arbitrary sized line with fgets()? You can't. The buffer to fgets() gets allocated before attempting to fill it and can always be filled before reaching a newline. You can use std::getline() to read an arbitrary long line, however. If you just want to skip the line, you can use in.ignore(std::numeric_limits<std::streamsize>::max(), '\n') when using std::istream. Off-hand I don't know if there is a similar operation for FILE*.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top