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 vect开发者_如何转开发or 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;
}
If you imbue() a file stream after the file is opened the imbue() will silently fail.
You must do the imbue() then open the file:
std::basic_ifstream<float, traits_type> input;
std::locale loc(std::locale(), new cvt());
input.imbue(loc);
// Open after the imbue()
input.open( pszDataFile, std::ios::binary );
Your second problem is you are confusing the terms binary file:
This code reads a stream of text data (i.e. a text file) using the operator >>
std::copy(std::istreambuf_iterator<float>(input),
std::istreambuf_iterator<float>( ),
std::back_inserter(fvBuffer));
The use of std::ios::binary
when you open the file only affects the how the 'end of line sequence' (EOLS) is generated it has nothing to do with the nature of the file. Though because you specify it the '\n' character is not converted into the EOLS which is useful when you are generating binary files.
So the short answer is you better by reading a text stream from a file.
The reason your vector is shorter than what you expect is because the stream reading encountered an error and as a result stopped responding to read requests.
Additionally I can't get your code to compile.
So you are doing something else non-standard.
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"));
}
}
精彩评论