10

我发现在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 位,他们为什么要进行这种转换!?我不知道 ))

4

3 回答 3

7

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

_BADOFF 被定义为 64 位类型,它只是被分配了一个愚蠢的值。

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

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

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

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

所以对库的修复可能是修复演员表(假设这样做没有其他副作用),但为了解决这个问题,你只需要避免寻找底部 32 位的位置被设置。从我所见,它会寻求超越这一点。

于 2012-12-12T11:51:18.427 回答
5

这确实是Visual C++ 2010的一个bug。两年前在Microsoft Connect上报道过: std::fstreamuse 32-bit int as pos_type even on x64 platform”(这个bug的标题不正确;症状其实就是这个bug引起的中_FPOSOFF)。

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

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

如果可以的话,建议您升级到 Visual C++ 2012。

于 2012-12-12T18:41:32.590 回答
2

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

  1. 在 stdio.h 中进行修复

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

  2. 移到VS2012(这也很可悲)

    这是一个错误,已在 Visual Studio 2012 中修复:_FPOSOFF 现在转换为 long long,因此 > 避免了截断。——詹姆斯·麦克内利斯

于 2012-12-12T18:43:42.387 回答