seekg无法正确处理4294967295字节的文件

时间:2012-12-12 10:35:32

标签: c++ visual-studio-2010 seekg

我发现在VS2010中,当打开4294967295字节的文件时,seekg功能无法正常工作。

我正在使用简单的代码:

#include <iostream>
#include <fstream>
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    std::ifstream file;

    // cmd: fsutil file createnew tmp.txt 4294967295
    file.open(L"c:/tmp.txt", ifstream::in | ifstream::binary);

    if(!file.is_open())
        return -1;

    file.seekg(0, std::ios::end);

    auto state = file.rdstate();

    // this condition shoots only when size of the file is equal to 4294967295
    if((state & ifstream::failbit)==ifstream::failbit)
    {
        std::cout << "seekg failed";
    }

    // after seekg failed, tellg returns 0
    std::streampos endPos = file.tellg();

    return 0;
}

4294967294和4294967296文件的相同代码没有任何问题。

有人知道这个问题的解决方案吗?

更新

看起来这个问题就在这里:

template<class _Statetype>
class fpos
{
 __CLR_OR_THIS_CALL operator streamoff() const
 { // return offset
 return ((streamoff)(_Myoff + _FPOSOFF(_Fpos)));
 }
}

完全在

_FPOSOFF(_Fpos)

,其中

#define _FPOSOFF(fp) ((long)(fp))

所以它需要4294967295并将其转换为-1!

换句话说,这样的代码将失败

//returns -1, even if sizeof(fpos_t)=8
fpos_t pos = _FPOSOFF(4294967295);

_Myoff,_Fpos,streamoffset是64位

如果所有类型都是64位,为什么他们会进行此转换!?我不知道))

3 个答案:

答案 0 :(得分:7)

内部流实现有一个const'_BADOFF',它等于0xffffffff,当搜索失败时返回。在这种情况下,搜索成功,但搜索的返回值等于失败代码,这导致流包装器错误地设置其失败代码。

_BADOFF被定义为64位类型,它被赋予了一个愚蠢的值。

作为一种解决方法,您可以寻找1字节短路,然后读取一个字节。

file.seekg(-1, std::ios::end);
char temp; file >> temp;

但请注意,此错误将在任何时候显示特定的文件偏移量,因此如果您在随机位置搜索较大的文件,它仍然可能会出现问题。例如,如果您的文件大一个字节,则此-1搜索将失败,因此这不是一般解决方案。

OP已经延长了他们的问题,所以我会扩展我的答案。是的,在比较之前使用不安全的转换来转换搜索值。这似乎不会影响在文件中超出该点的搜索能力,因为它仅用于与错误值进行比较 - 流中仍然具有正确的偏移量。然而,它似乎确实是_BADOFF首先可疑的根本原因,因为_BADOFF在源中被设置为'-1',并且将遭受相同的转换,截断为0xffffffff。

因此修复libs可能是为了修复强制转换(假设没有其他副作用),但为了解决问题,你只需要避免寻找底部的位置设置了32位。从我能看到的情况来看,它将寻求超越这一点。

答案 1 :(得分:5)

这确实是Visual C ++ 2010中的一个错误。两年前在Microsoft Connect上报告过:"std::fstream use 32-bit int as pos_type even on x64 platform"(错误的标题不正确;症状实际上是由{{1}中的这个错误引起的})。

在Visual C ++ 2012中修复了此错误,其中_FPOSOFF定义为:

_FPOSOFF

如果能够这样做,建议您升级到Visual C ++ 2012。

答案 2 :(得分:1)

目前有两个不太好的解决方案

  1. 在stdio.h中修复

      

    #define _FPOSOFF(fp)((long long)(fp))

  2. 转到VS2012(这也很难过)

      

    这是一个错误,并在Visual Studio 2012中修复:_FPOSOFF现在转换为long long,因此&gt;避免截断。 - 詹姆斯麦克尼利斯