为什么basic_ifstream会给我错误的结果?

时间:2011-06-02 13:22:13

标签: c++ file binary ifstream

我有一个二进制文件。上半部分存储了2288 * 2288个经度浮点值,下半部分占据了相同数量的纬度浮点值。我使用以下代码将它们加载到浮点向量中。它可以像魅力一样运行,但给了我不正确的结果。关于我的二进制文件,浮点向量应该填充总共2288 * 2288 * 2 = 10469888个元素,但只有159005,它们的所有值都是相同的200.0000。你能解释我的代码有什么问题吗?

提前谢谢!

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;
}

2 个答案:

答案 0 :(得分:1)

如果在打开文件后imbue()文件流,imbue()将无声地失败。

您必须执行imbue()然后打开文件:

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 );

你的第二个问题是你混淆了二进制文件:

此代码使用运算符&gt;&gt;

读取文本数据流(即文本文件)
std::copy(std::istreambuf_iterator<float>(input),          
          std::istreambuf_iterator<float>( ),         
          std::back_inserter(fvBuffer)); 

打开文件时std::ios::binary的使用仅影响生成“行结束序列”(EOLS)的方式,它与文件的性质无关。虽然因为你指定它,'\ n'字符不会转换为EOLS,这在生成二进制文件时很有用。

因此,通过从文件中读取文本流,您可以更好地回答。

您的矢量比您预期的短的原因是因为流读取遇到错误并因此停止响应读取请求。

另外,我无法编译你的代码 所以你正在做一些非标准的事情。

答案 1 :(得分:0)

要使std :: basic_ifstream工作,你必须定义你的trait_type,以便它提供输入流所需的一切,而且我不确定它是否可行。这将远远超过codecvt<float, char, mbstate_t>(您似乎已经认为已经存在,而标准只需要wchar_t,char和char,char特化)。

如果你想要一个二进制输入迭代器,你必须自己编写一个来处理basic_ifstream,就像这样(运行并给出预期结果,但不进一步调试):

#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"));
 }
}