Search code examples
c++filebinaryifstream

Why basic_ifstream show me wrong results?


I have a binary file. There are 2288*2288 longitude float values stored in top half section, and the same number of latitude float values occupied the bottom half. I used the following code to load them into a float vector. It can run like a charm, but gave me incorrect results. With regard to my binary file, the float vector should be filled with a total of 2288*2288*2=10469888 elements, but only 159005, all their values are the same 200.0000. Would you please explain what's wrong with my code?

Thank you in advance!

bool LoadData(const char* pszDataFile)
{   
    typedef char_traits<float> traits_type;
    typedef std::codecvt<float, char, mbstate_t> cvt;

    std::basic_ifstream<float, traits_type> input( pszDataFile, std::ios::binary );
    std::locale loc(std::locale(), new cvt());
    input.imbue(loc);

    std::vector<float> fvBuffer;    

    // Copies all data into buffer 
    std::copy(std::istreambuf_iterator<float>(input),          
              std::istreambuf_iterator<float>( ),         
              std::back_inserter(fvBuffer)); 

    long nSzie = fvBuffer.size();  // Wrong vector size (159005)

    return true;
}

Solution

  • To make std::basic_ifstream works, you have to define your trait_type so that it provides everything expected by input stream, and I'm not sure that it will be possible. That will be far more than just a codecvt<float, char, mbstate_t> (which you seem to think is already present while the standard demand only the wchar_t, char and char, char specializations).

    If you want a binary input iterator, you'll have to write one yourself to work with basic_ifstream, something like this (run and give the expected result, but not debugged further):

    #include <fstream>
    #include <algorithm>
    #include <vector>
    #include <iterator>
    #include <iostream>
    
    template <typename T>
    class BinaryInputIterator
        : public std::iterator<std::input_iterator_tag, T, std::ptrdiff_t,
                               const T*, const T&>
    {
    public:
        BinaryInputIterator();
        BinaryInputIterator(std::istream&);
        // Compiler generated version OK:
        // BinaryInputIterator(BinaryInputIterator const& other);
        // BinaryInputIterator& operator=(BinaryInputIterator const& other);
        ~BinaryInputIterator();
    
        T const& operator*() const;
        T const* operator->() const;
        BinaryInputIterator& operator++();
        BinaryInputIterator operator++(int);
    
    private:
        std::istream* myStream;
        T myValue;
    
        friend bool operator==
           (BinaryInputIterator const& l, BinaryInputIterator const& r)
        {
            return ((l.myStream == NULL && (r.myStream == NULL || !*r.myStream))
                    || (r.myStream == NULL && (l.myStream == NULL || !*l.myStream)));
        }
        friend bool operator!=
           (BinaryInputIterator const& l, BinaryInputIterator const& r)
        {
            return !(l == r);
        }
    };
    
    template <typename T>
    BinaryInputIterator<T>::BinaryInputIterator()
        : myStream(0)
    {}
    
    template <typename T>
    BinaryInputIterator<T>::BinaryInputIterator(std::istream& is)
        : myStream(&is)
    {
        myStream->read(reinterpret_cast<char*>(&myValue), sizeof myValue);
    }
    
    template <typename T>
    BinaryInputIterator<T>::~BinaryInputIterator()
    {}
    
    template <typename T>
    T const& BinaryInputIterator<T>::operator*() const
    {
        return myValue;
    }
    
    template <typename T>
    T const* BinaryInputIterator<T>::operator->() const
    {
        return &myValue;
    }
    
    template <typename T>
    BinaryInputIterator<T>& BinaryInputIterator<T>::operator++()
    {
        myStream->read(reinterpret_cast<char*>(&myValue), sizeof myValue);
        return *this;
    }
    
    template <typename T>
    BinaryInputIterator<T> BinaryInputIterator<T>::operator++(int)
    {
        BinaryInputIterator result(this);
        ++*this;
        return result;
    }
    
    int main()
    {
     {
        std::ofstream os("foo.dta");
        std::vector<float> vect1;
        vect1.push_back(4.2);
        vect1.push_back(3.14);
        os.write(reinterpret_cast<char*>(&vect1[0]), sizeof(float)*vect1.size());
     }
     {  
        std::ifstream is("foo.dta");
        std::vector<float> vect2;
        std::copy(BinaryInputIterator<float>(is),
                  BinaryInputIterator<float>(),
                  std::back_inserter(vect2));
        std::copy(vect2.begin(), vect2.end(), std::ostream_iterator<float>(std::cout, "\n"));
     }
    }