【问题标题】:Why does this code always return file size zero?为什么这段代码总是返回文件大小为零?
【发布时间】:2015-03-16 15:31:10
【问题描述】:

为什么,当我使用以下代码 sn-p 时,无论文件大小如何,结果都是零,但是当我在 open() 中删除 ios::binary 时,它会执行它应该做的事情?

fstream f1;    
streampos begin, end;
f1.open("file1", ios::binary);
f1.seekg(0, ios::beg);
begin = f1.tellg();
f1.seekg(0, ios::end);
end = f1.tellg();
f1.close();
cout << end - begin << endl;

【问题讨论】:

  • 这真的让我感到困惑,人们如何编写不检查错误条件的代码。只是……为什么?!

标签: c++ file binary fstream operation


【解决方案1】:

我假设“当我删除 ios::binary”时,您的意思是您删除了整个论点:

f1.open("file1");

函数open() 有两个参数——文件名和模式。模式一的默认参数为std::ios_base::in | std::ios_base::out。因此,如果您不指定任何内容,则会使用此默认值。

如果您指定ios::binary,但是,您替换默认参数。由于您既没有指定in 也没有指定outopen() 调用失败。在 open() 周围加上 if() 会告诉你——记住你应该总是检查 I/O 错误。

【讨论】:

  • 哈哈...一个漂亮的演示为什么错误检查很重要。
  • thanx Angew 但为什么这段代码有效? ifstream myfile ("example.bin", ios::binary);
  • @MojtabaKarimdokht 很明显,您将使用std::basic_ifstream 进行输入,因此构造函数通过rdbuf()-&gt;open(s, mode | ios_base::in) 在缓冲区上调用open,在您的情况下,模式为ios_base::binary
【解决方案2】:

如果你得到一个大小为0,检查文件是否打开...

#include<iostream>
#include<fstream>

using namespace std;

int main(){

    fstream f1;
    streampos begin, end;
    f1.open("Data.txt", ios::binary);
    if (f1.is_open()) {
        cout << "Open" << endl;
    }
    f1.seekg(0, ios::beg);
    begin = f1.tellg();
    f1.seekg(0, ios::end);
    end = f1.tellg();
    f1.close();
    cout << end - begin << endl;

    system("pause");
}

如果它没有打开,你可能已经尝试打开一个文本文件。

在文本文件中,ios::binary 标志不包含在打开模式中。文本文件用于存储文本数据,当对它们进行二进制输入/输出操作时,可能会导致格式转换。

【讨论】:

  • 是什么让您认为以二进制模式打开任何文件都是一个问题?二进制模式是常态。文本模式仅用于在阅读时将特定于平台的行尾字符转换为'\n',并在写入时再次返回。文件本身就是磁盘上的(二进制)数据。
  • 当我尝试打开带有二进制标志的文本文件时,file.is_open() 返回 false。删除该标志后,文件将打开。
  • 什么操作系统和文件系统?必须是一个非常奇特的组合,以区分像这样的二进制文件和文本文件。或者您是否在做与 OP 相同的错误并将 just ios::binary 传递给 fstream::open()(没有 ios::inios::out)?
【解决方案3】:

std::ios_base::binary 本身不是std::basic_fstream 的有效打开模式。有效的开放模式组合可以在表 132 中找到:

std::basic_fstream 的构造函数及其open() 方法都将内部std::basic_filebuf 上的open() 方法转发到rdbuf()-&gt;open(s, mode),其中mode 是开放模式。从表中可以看出,mode(其中模式为ios_base::binary)本身并不是一个有效的标志。当文件缓冲区确定打开失败时:

NTBS modstrmode &amp; ~ios_base::ate 确定,如表 132 所示。如果 mode 不是表中所示的某些标志组合,则打开失败。

在打开文件时mode 没有与out | in 进行位或运算的原因是,不清楚您是否要使用流进行输入或输出(假设您知道自己想要什么)。由于模式不是有效的标志组合,std::basic_filebuf::open() 返回一个空指针。这由流接收,然后调用setstate(std::ios_base::failbit)

[..] 调用rdbuf()-&gt;open(s, mode)。如果该函数返回一个空指针,则调用setstate(failbit)

当流处于失败状态时,其tell 方法返回-1。这就是为什么你在减法时得到0

如果你想要的只是大小,这是打开它的正确方法:

std::fstream f1("file1", std::ios_base::in | std::ios_base::ate | std::ios_base::binary);
std::cout << f1.tellg();

【讨论】:

  • 天哪!我不知道这个问题有这么复杂的长可怕背景! :O
猜你喜欢
  • 1970-01-01
  • 2017-03-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-18
相关资源
最近更新 更多