tellg()函数给出错误的文件大小?

Eli*_*ior 23 c++ file ifstream

我做了一个示例项目,将文件读入缓冲区.当我使用tellg()函数时,它给我一个比读取函数实际读取的值更大的值.我认为有一个错误.

这是我的代码:

编辑:

void read_file (const char* name, int *size , char*& buffer)
{
  ifstream file;

  file.open(name,ios::in|ios::binary);
  *size = 0;
  if (file.is_open())
  {
    // get length of file
    file.seekg(0,std::ios_base::end);
    int length = *size = file.tellg();
    file.seekg(0,std::ios_base::beg);

    // allocate buffer in size of file
    buffer = new char[length];

    // read
    file.read(buffer,length);
    cout << file.gcount() << endl;
   }
   file.close();
}
Run Code Online (Sandbox Code Playgroud)

主要:

void main()
{
  int size = 0;
  char* buffer = NULL;
  read_file("File.txt",&size,buffer);

  for (int i = 0; i < size; i++)
    cout << buffer[i];
  cout << endl; 
}
Run Code Online (Sandbox Code Playgroud)

Jam*_*nze 55

tellg不报告文件的大小,也不报告从字节开始的偏移量.它会报告一个令牌值,以后可以用它来寻找同一个地方,仅此而已.(甚至不能保证您可以将类型转换为整数类型.)

至少根据语言规范:在实践中,在Unix系统上,返回的值将是从文件开头的字节偏移量,在Windows下,它将是从文件开头到文件开头的偏移量.二进制模式.对于Windows(以及大多数非Unix系统),在文本模式下,tellg返回的内容与必须读取到该位置的字节数之间没有直接和直接的映射 .在Windows下,您真正​​可以依赖的是,该值将不小于您必须读取的字节数(在大多数情况下,不会太大,尽管它可能高达两倍以上).

如果确切地知道您可以读取多少字节很重要,那么可靠地执行此操作的唯一方法是阅读.您应该可以使用以下内容执行此操作:

file.ignore( std::numeric_limits<std::streamsize>::max() );
std::streamsize length = file.gcount();
file.clear();   //  Since ignore will have set eof.
file.seekg( 0, std::ios_base::beg );
Run Code Online (Sandbox Code Playgroud)

最后,关于您的代码的另外两个评论:

一,行:

*buffer = new char[length];
Run Code Online (Sandbox Code Playgroud)

不应该编译:你声明buffer是a char*,所以*buffer有类型char,而不是指针.鉴于你似乎在做什么,你可能想要声明bufferchar**.但更好的解决方案是将其声明为a std::vector<char>&或a std::string&.(这样,您也不必返回大小,如果存在异常,则不会泄漏内存.)

其次,最后的循环条件是错误的.如果你真的想一次读一个角色,

while ( file.get( buffer[i] ) ) {
    ++ i;
}
Run Code Online (Sandbox Code Playgroud)

应该做的伎俩.更好的解决方案可能是读取数据块:

while ( file.read( buffer + i, N ) || file.gcount() != 0 ) {
    i += file.gcount();
}
Run Code Online (Sandbox Code Playgroud)

甚至:

file.read( buffer, size );
size = file.gcount();
Run Code Online (Sandbox Code Playgroud)

编辑:我刚刚注意到第三个错误:如果您无法打开文件,则不会告诉调用者.至少,您应该将其设置size为0(但某种更精确的错误处理可能更好).

  • `tellg()`返回一个`streampos`对象,[这里](http://www.cplusplus.com/reference/ios/streampos/)它声明«*这个类的对象支持从int*构造和转换»,至少声明*"它甚至不能保证你可以将类型转换为整数类型"*似乎不是真实的. (9认同)
  • @AndrewHenle,我指出“语句_“甚至不能保证您可以将类型转换为整数类型”_似乎并不真实”,而不是“这种转换产生的整数值是大小文件的”,正如你所说。 (4认同)
  • @法比奥A。[C++14 27.9.1.1,p2](https://port70.net/~nsz/c/c%2B%2B/c%2B%2B14_n3936.txt):“读写受控序列的限制通过类 `basic_filebuf&lt;charT,traits&gt;` 的对象进行的操作与使用标准 C 库文件进行读写相同。” (2认同)
  • (续)[C11,7.21.9.4p2](https://port70.net/~nsz/c/c11/n1570.html#7.21.9.4p2):“对于文本流,其文件位置指示符包含未指定的信息,可由 fseek 函数使用,用于将流的文件位置指示器返回到 ftell 调用时的位置;两个此类返回值之间的差异不一定是写入或读取的字符数的有意义的度量。” (2认同)
  • (续)[C11 7.21.9.2p3](https://port70.net/~nsz/c/c11/n1570.html#7.21.9.2p3):“二进制流不需要有意义地支持带有whence值的fseek调用共 SEEK_END。” [C11,脚注 268](https://port70.net/~nsz/c/c11/n1570.html#note268):“将文件位置指示器设置为文件结尾,与 `fseek(file, 0) 一样, SEEK_END)`,对于二进制流有未定义的行为......” (2认同)
  • (续)因此,您不能使用“tellg()”来获取文本流的字节数,也不能使用“seekg()”来获取二进制流的末尾。我想今天对你来说是美好的一天 - 你学到了一些你以前不知道的东西 (2认同)

fen*_*fen 20

在 C++17 中有std::filesystem file_size方法和函数,所以可以简化整个任务。

使用这些函数/方法,有机会不打开文件,而是读取缓存数据(尤其是使用该std::filesystem::directory_entry::file_size方法)

这些功能也只需要目录读取权限,而不需要文件读取权限(也是tellg()如此)