【问题标题】:C style, C++ streams or Win32 API File I/O?C 风格、C++ 流或 Win32 API 文件 I/O?
【发布时间】:2011-09-07 07:13:30
【问题描述】:

我阅读了C++ Streams vs. C-style IO?(以及其他页面)试图帮助我决定在我正在处理的项目中实现某些文件 IO 的方式。

背景 我对 C++ 和 Windows 编程相当陌生,我一直在 C 和命令行应用程序中工作。提前为这个问题的n00b-ness道歉。

问题 我想读取一个文本文件,处理内容并输出到另一个(新)文本文件。我在 Win32 环境中工作(在可预见的未来这不会改变)并且正在编写应用程序以通过 _T 样式宏来识别 Unicode。 “处理”可能包括插入/附加/删除文本行,最多为 128 个字符。

问题 我更喜欢写一些健壮的东西,所以 I/O 错误处理是一个考虑因素。我认为我需要远离 C 风格的文件 I/O,如果只是为了简化代码和类型检查——即在更 OO POV 中处理这个问题。与 C++ 流函数(如果有)相比,使用 Win32 API 函数有哪些优势?你能为这两种方法推荐一个好的入门书吗? (我的谷歌搜索给我留下了一点信息过载)

非常感谢

【问题讨论】:

  • 我应该提到,虽然行长度会受到限制(并且很小),但文件长度会变化很大,但通常相当大。
  • 你能估计一下“相当大”的量级是什么意思吗?例如几十兆,几百兆,千兆字节,几十千兆字节,……几十兆兆字节?
  • @Ben 是的,“相当大”完全是模棱两可的,抱歉,10s 的 Mb,但必须在实时环境中处理,所以是的,性能是一个考虑因素。

标签: c++ winapi file-io


【解决方案1】:

与 C++ 流函数(如果有的话)相比,使用 Win32 API 函数有哪些优势?

  1. 速度
  2. 能够使用重叠 I/O 一次处理多个操作而无需线程(以及同步的复杂性)
  3. 速度
  4. 更具体的错误代码
  5. 速度
  6. 速度
  7. 低依赖足迹(与 MSVC++ 7.x、8.0、9.0、10.0 以及可能的大多数其他供应商相比)
  8. 速度

【讨论】:

  • 而缺点是'没有机会将代码移动到 Windows 以外的任何地方'。目前尚不清楚这对 OP 是否重要。
  • @Jonathan:由于他没有询问 Win32 API 的缺点,我希望可移植性问题对@Stephen 来说是显而易见的,他已经确定这不是一个压倒一切的因素。
  • 我不明白 windows.h 怎么可能被描述为“低依赖足迹”。
  • @sean:只有度数。如果您使用 C 或 C++ 标准库,则必须以某种方式部署它们。 @Neil:除了依赖于 C 和 C++ 库本身之外,使用 C 或 C++ 标准库的代码还间接依赖于 windows.h 相关的所有内容。此外,无需重新分发在 windows.h 中找到的任何内容,相应的 DLL 已经在系统上。而 C 和/或 C++ 库必须包含在应用程序中。这可以将安装程序增加几个数量级。
  • @Neil:不,您的用户负责查找和安装依赖项。这是 (1) 更多的负担,并且 (2) 大多数 Windows 用户完全出乎意料。
【解决方案2】:

使用 C++ 流 I/O。写入文本文件几乎不会对 I/O 库造成压力,而且您在代码清晰、类型安全以及几乎不需要编写任何内容即可完成工作这一事实方面获得了巨大的好处。作为一个副作用,你的代码可能会更便携和更容易理解,所以如果你必须在这里询问它,你会得到更好的答案。

【讨论】:

  • “几乎不会强调 I/O 库”...有时是真的,有时不是,真的取决于有多少 I/O。例如,我必须每天使用一个使用 C++ iostreams 进行文本模式输出的应用程序,写出 2GB 的数据需要超过 4 个小时。我的基于 Win32 的代码可以在大约 2 分钟内读取并解析该数据文件。
  • @Ben 你有没有想过写这个应用程序的人不知道他在做什么?
  • @BenVoigt :听起来像std::endl 惨败。 ;-]
  • 4 小时写入 2 GB == OUCH。在那里的第一周,我会用 Ruby 重写这该死的东西。
  • @Neil:我突然想到,开发人员从广告导出功能中受益,同时让导出数据和使用另一个分析包变得很痛苦。我想我应该使用 ProcMon 并检查是否有很多微小的写入(endl 刷新会导致)。但实际上,iostreams 的开销解释了这个问题,使用 iostreams 读取数据的程序非常慢,然后改用 Win32 获得了 30 倍的加速。
【解决方案3】:

从更广泛的角度来看,如果您需要一个没有额外依赖项的小型应用程序,直接使用 Win32 会很好。

对于 C++ iostreams 做得更好的任何事情,您可能想看看 Boost::Spirit。似乎它具有 iostream 的所有类型安全性,并且性能要好得多。

这里确实有两个问题:文件 I/O 和文本处理。 Win32 在第一个方面做得非常好,对第二个没有帮助。 Boost::Spirit 在第二个方面做得很好。 C++ iostreams 在这两个任务中都是微不足道的,除非可移植性是最重要的特性,否则请避免使用它们。

【讨论】:

  • @Ben 我认为您既不了解 Spirit 也不了解 C++ iostream。
  • @Neil:我可能将 Spirit 与其他 Boost 库之一(例如 Qi)混淆了。我知道我已经看到 Boost 库之一的基准测试(不是lexical_cast!)在文本解析方面的吞吐量比例如更高。 strtod.
  • here 是有问题的参考。似乎我说 Boost::Spirit 是正确的,因为 Qi 是该库的一个子集。
  • @Ben 嗯? lexical_cast 不是 iostreams 或 Spirit 的一部分,它不进行解析。您似乎将转换与解析混为一谈。
  • @Neil:我说它是Boost 的一部分,我错了吗?而string s = "-1.45e67"; double d = lexical_cast<double>(s); 是文本解析,不是吗?但我提到 lexical_cast 只是说并非所有 Boost 提供的设施都具有高性能。
【解决方案4】:

只是为了提供一个粗略的基准 - 这段代码必须是效率最低的:

#include <iostream>
using namespace std;

unsigned int MB = 1024 * 1024;
unsigned int GB = MB * 1024;

int main() {
    char c = 'x';
    for ( unsigned int i = 0; i < GB; i++ ) {
        cout << c;
    }
}

调用时花了大约 4 分钟将数据写入文本文件:

myprog > file.txt

在我几乎不是最先进的笔记本电脑上。

【讨论】:

  • 我假设这是 mingw 的?如果你有时间,你会回复my question comparing number->string conversion performance of iostream, sprintf, and tuned code吗?我很想看看 mingw 的票价如何。我建议最重要的情况是问题中的 iostreams 和 sprintf 实现以及接受的答案。
  • 顺便说一句,写入千兆字节的磁盘 I/O 时间不超过 12 秒(假设您的磁盘碎片级别没有超出图表)......所以在这种情况下,iostreams 正在减慢一切20 倍……甚至还没有进行任何格式化。
猜你喜欢
  • 2023-03-08
  • 1970-01-01
  • 1970-01-01
  • 2015-05-24
  • 1970-01-01
  • 2012-01-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多