C++ 和 C 文件 I/O

C++ and C file I/O

提问人:Chaithra 提问时间:3/3/2009 最后编辑:YamanekoChaithra 更新时间:11/14/2023 访问量:11579

问:

C++ 文件 I/O 比 C 文件 I/O 更难。 那么在C++中,为文件 I/O 创建一个新库是否有用?我的意思是谁能告诉C++文件 I/O 有什么好处吗?<fstream>

C++ 文件 IO

评论

1赞 3/3/2009
强硬?我不这么认为。。o_O
2赞 Konrad Rudolph 3/3/2009
似乎没有人知道你说的“更强硬”是什么意思。想详细说明吗?目前,你的问题只是乞求开始一场火焰战争。
0赞 Joe DF 3/8/2013
C 更快...cybertiggyr.com/ios0/index.html

答:

0赞 EFraim 3/3/2009 #1

很多。缺点也是。有关详细信息,请参阅 C++ 语言常见问题解答。简而言之:类型安全和用户定义的类型。

评论

0赞 Anonymous 3/3/2009
准确地说,是幻觉型安全。
0赞 EFraim 3/3/2009
我不太明白“幻觉”这个词。这是非常真实的。当然,向自己的脚开枪总是一种选择。
0赞 David Allan Finch 3/3/2009
由于事物可以通过临时性自动投射的方式,事物可以跳转类型。
0赞 j_random_hacker 3/4/2009
@David:东西可以跳转类型,但标准库中没有任何东西可以这样做,通常的智慧是将用户定义的转换限制在最低限度以避免这种情况。
0赞 j_random_hacker 3/4/2009
@David:OTOH 我认为看似合理的代码“std::ofstream(”somefile“) << ”abc“);' 在大多数实现中将”0“输出到 somefile 是一个错误,因为深C++怪异(具体来说,一些 operator<<() 重载是 iostream 的成员,而另一些是自由函数)。
1赞 Mykola Golubyev 3/3/2009 #2

std::ifstream 和 std::ofstream 已在 STL 库中。您不必创建自己的。

主要优点是所有输出和输入都是类型安全的。

1赞 dirkgently 3/3/2009 #3

C 和 C++ 是两种不同的语言。C++ 文件 io 需要一些时间来适应,但是一旦你使用算法、异常等,它们往往会非常自然地到位。

18赞 David Allan Finch 3/3/2009 #4

意见

我不知道有任何使用 C++ 流的真实项目。它们太慢且难以使用。有几个较新的库,如 FastFormatBoost 版本,声称更好,上一期 ACCU Overload 杂志中有一篇关于它们的文章。就我个人而言,在过去的 15 年左右的 C++ 中使用了 c FILE 库,我认为没有理由改变。

速度

这里有一个小测试程序(我快速拼凑起来)来展示基本的速度问题:

#include <stdio.h>
#include <time.h>

#include<iostream>
#include<fstream>

using namespace std;

int main( int argc, const char* argv[] )
    {
    const int max = 1000000;
    const char* teststr = "example";

    int start = time(0);
    FILE* file = fopen( "example1", "w" );
    for( int i = 0; i < max; i++ )
        {
        fprintf( file, "%s:%d\n", teststr, i );
        }
    fclose( file );
    int end = time(0);

    printf( "C FILE: %ds\n", end-start );

    start = time(0);
    ofstream outdata;
    outdata.open("example2.dat");
    for( int i = 0; i < max; i++ )
        {
        outdata << teststr << ":" << i << endl;
        }
    outdata.close();
    end = time(0);

    printf( "C++ Streams: %ds\n", end-start );

    return 0;
    }

以及我电脑上的结果:

C FILE: 5s
C++ Streams: 260s

Process returned 0 (0x0)   execution time : 265.282 s
Press any key to continue.

正如我们所看到的,这个简单的例子慢了 52 倍。我希望有办法让它更快!

注意:在我的示例中将 endl 更改为“\n”改进了 C++ 流,使其仅比 FILE* 流慢 3 倍(感谢 jalf),可能有办法使其更快。

使用难度

我不能说 printf() 并不简洁,但它更灵活 (IMO) 并且更易于理解,一旦你通过了宏代码的初始 WTF。

double pi = 3.14285714;
    
cout << "pi = " << setprecision(5)  << pi << '\n';
printf( "%.5f\n", pi );
    
cout << "pi = " << fixed << showpos << setprecision(3) << pi << '\n'; 
printf( "%+.3f\n", pi );
    
cout << "pi = " << scientific << noshowpos << pi<< '\n';
printf( "%e\n", pi );

问题

是的,可能需要更好的C++库,可能是FastFormat就是那个库,只有时间会证明一切。

戴夫

评论

18赞 jalf 3/3/2009
你的比较是有缺陷的。C 和 C++ 版本不做同样的事情。c++ 版本在每行 (endl) 之后刷新缓冲区。有时,阅读有关您使用的代码的文档是个好主意。
10赞 jalf 3/3/2009
称 printf 更灵活也是无稽之谈。它不适用于用户定义的类型。这很难灵活。它远不如 iostreams 灵活。我认为C++版本更容易理解。我能猜到setprecision是做什么的。%+.3 不太明显。
8赞 Jon Trauntvein 3/3/2009
std::endl 比简单地插入换行符要慢,因为 std::endl 被定义为同时刷新流。
7赞 Benj 10/18/2011
@David:我意识到这是很久以前的事了。但我只是运行了上面的测试程序(没有 endl)并得到了非常相似的结果。在调试模式下,我得到了与您类似的结果,但在 VC2010 的发布模式下,我得到了 C 和 C++ 的相同结果。我能问一下你最初是在调试还是发布中运行这个吗?
2赞 Joe DF 3/8/2013
对于输入和输出,C 比 C++ 更快。cybertiggyr.com/ios0/index.html
9赞 anon 3/3/2009 #5

对我来说,消除缓冲区溢出似乎是 C++ 的一大胜利。

评论

0赞 David Allan Finch 3/3/2009
那么动态存储的额外成本呢?您是否合理地计算了使用它的成本。请参阅:上一个 ACCU 的 Overload/ 中的 /FastFormat。
0赞 j_random_hacker 3/3/2009
我猜你说的是gets()。是否有其他标准 C I/O 函数可能会使缓冲区溢出?
0赞 Mikeage 3/3/2009
当然,scanf(或fscanf),如果你不小心的话。
0赞 j_random_hacker 3/4/2009
@Mikeage:好点子,%s in ...scanf() 是等待发生的缓冲区溢出。
8赞 lakshmanaraj 3/3/2009 #6

请看一下

http://www.ddj.com/cpp/184403651

那么您将更喜欢 C++ I/O 而不是 C I/O。

简而言之,如果您在读取或写入之前知道数据大小并且速度,则首选 C。 如果您不知道数据大小和高效代码,则首选 C++。

2赞 Jon Trauntvein 3/3/2009 #7

printf()/fwrite 样式 I/O 和 C++ IO 流格式之间的性能差异在很大程度上取决于实现。一些实现(例如可视化 C++)在 FILE * 对象之上构建其 IO 流,这往往会增加其实现的运行时复杂性。但是请注意,以这种方式实现库没有特别的限制。

在我个人看来,C++ I/O 的好处如下:

  • 如前所述,类型安全。
  • 实施的灵活性。可以编写代码来执行特定的格式设置或输入到泛型 ostream 或 istream 对象或从泛型 ostream 或 istream 对象输入。然后,应用程序可以使用任何类型的派生流对象调用此代码。如果我针对文件编写和测试的代码现在需要应用于套接字、串行端口或其他类型的内部流,则可以创建特定于该类型 I/O 的流实现。
  • 语言环境设置的灵活性:在我看来,使用单一全局语言环境的 C 方法存在严重缺陷。我遇到过这样的情况:我调用了库代码(DLL),这些代码更改了代码下的全局区域设置,并完全搞砸了我的输出。C++ 流允许您将任何语言环境灌输给流对象。
10赞 jalf 3/3/2009 #8

为了回应David Allan Finch的回答,我修复了他的基准测试代码中的一个错误(他在每一行之后刷新了C++版本中的流),并重新运行了测试:

C++ 循环现在如下所示:

start = time(0);
{
    ofstream outdata("example2.txt");
    for( int i = 0; i < max; i++ )
    {
        outdata << teststr << ":" << i << "\n"; // note, \n instead of endl
    }
}
end = time(0);

我运行了 10000000 次迭代(比原始代码多 10 倍,因为否则,数字太小了,以至于 time() 糟糕的分辨率无法给我们任何有意义的东西)) 输出为:

G++ 4.1.2:
C FILE: 4s
C++ Streams: 6s

MSVC9.0:
C FILE: 10s
C++ Streams: 23s

(注意,MSVC 版本在我的笔记本电脑上运行,硬盘速度明显较慢)

但这给了我们 1.5-2.3 倍的性能差异,具体取决于实现。和其他外部因素。

评论

0赞 David Allan Finch 3/3/2009
在我的 UltraSparc 上,我得到 9 秒和 21 秒,使用 /tmp 我得到 5 秒和 16 秒。哦,我确实编辑了我的答案;)
2赞 skyscraper 8/7/2018 #9

每当我需要在 C++ 文件中获取输入/输出时,我只使用两行。

freopen("input.txt","r",stdin); // for input from file
freopen("output.txt","w",stdout);// for output from file

现在,您可以像往常一样从控制台扫描变量,并且您打印为输出的任何内容都将显示output.txt文件中。

所以我不认为 c++ 中的文件 I/O 很难,它比 c 容易得多。

评论

0赞 Andrew Henle 8/8/2018
freopen() 是标准的 C,而不是 C++,尽管它可以被 C++ 代码使用。我看不出如何发布重新分配的 C 代码,并使 C++ IO “比 c 更容易”的任何情况。充其量,它同样适用于两种语言。stdinstdout
0赞 skyscraper 8/8/2018
@AndrewHenle c++ 中的 freopen() 是在完全不同的头文件中定义的,这比 C 中的头文件更容易使用。
2赞 Andrew Henle 8/8/2018
C++ 中的 freopen() 是在完全不同的头文件中定义的你真的认为比?这似乎无关紧要。而且 - 在 GCC 的情况下 - 你完全错了,因为 cstdio 只是一些 C++ 语法糖包裹在 stdio.h. 周围。#include <cstdio>#include <stdio.h>
0赞 skyscraper 8/9/2018
@AndrewHenle好吧,同意,我想给你投赞成票,但不能。
0赞 Richard Eversole 8/11/2022 #10

更现代的更新....在GCC 9.2的快速C++基准测试中运行了类似的代码,现在C++ iostream显示为与等效C IO相比略快(1.1x)。注意:使用“\n”而不是 std::endl 以避免刷新问题。来自快速 c++ 基准测试的图表和实际代码

#include<iostream>
#include<fstream>

static void cIO(benchmark::State& state) {
  // Code inside this loop is measured repeatedly

  FILE *file{fopen("/tmp/example1.dat","w")};
  const char* teststr = "example";
  auto i{0};
  for (auto _ : state) {
   fprintf( file, "%s:%d\n", teststr, i++ );
  }
 fclose(file);
}
// Register the function as a benchmark
BENCHMARK(cIO);

static void cppIO(benchmark::State& state) {
  // Code before the loop is not measured
  std::ofstream outdata;
  outdata.open("/tmp/example2.dat");
  const char* teststr = "example";
  auto i{0};
  for (auto _ : state) {
   outdata << teststr << ":" << i++ << "\n";
  }
  outdata.close();
}
BENCHMARK(cppIO);
0赞 Hugh Granger 11/14/2023 #11

我没有看到提到的一件事是 cpp 流(至少是 cin、cout 等)使用 .std::ios_base::sync_with_stdio(false)