11

CreateFilevs fopenvs ofsteam-优势和劣势

我听说 CreateFile 功能强大但仅适用于 windows。
你能告诉我应该使用什么(在 Windows 上)以及为什么?

4

6 回答 6

8

这取决于你在做什么。对于顺序读取和写入文本文件,iostream 绝对是要走的路。对于涉及交易安全或非标准设备的任何事情,您必须直接访问系统(CreateFileopen)。即使这样,对于文本的顺序读取和写入,最好的解决方案是定义自己的streambuf,并将其与 iostream 一起使用。

我想不出任何fopen更可取的上下文。

于 2012-05-28T09:27:44.780 回答
4

除非您需要 Windows 文件函数提供的功能(例如重叠 I/O),否则我的建议是使用 C++ 中的 iostreams 或 C 中的FILEfopen和朋友)。

除了更便携之外,您还可以对文本文件使用格式化的输入/输出,而对于 C++,很容易为您的类重载输出/输入运算符。

于 2012-05-28T09:24:24.207 回答
3

如果您想使用 Windows 文件内存映射,您应该使用CreateFile(例如,HANDLE传递给CreateFileMapping API 的是 的返回值CreateFile)。此外,CreateFile提供比 C 和 C++ 标准文件 API 更高的自定义选项。

但是,如果您想编写可移植代码,或者如果您不需要 Windows 特定的功能,C 和 C++ 标准文件 API 就可以了。在一些测试中,当处理大数据时,我注意到 C++ I/O 流与原始 C 文件 API 的一些性能开销;如果您碰巧遇到这种情况,您可以简单地将原始 C 文件 API 包装在某个 C++ RAII 类中,并仍然在 C++ 代码中使用它。

于 2012-05-28T09:34:54.210 回答
2

除非您绝对需要 OS API 函数(如CreateFile)提供的额外功能,否则我建议您使用标准库函数(如fopenofstream)。这样,您的程序将更具可移植性。

我能想到的唯一真正的优势CreateFile是重叠的 I/O 和更细粒度的访问权限。

于 2012-05-28T09:31:40.130 回答
1

在大多数情况下,最好在 C 中使用 fopen 或在 C++ 中使用 ofstream。CreateFile 对共享和缓存提供了一些额外的控制,但不提供格式化功能。

于 2012-05-28T09:22:11.693 回答
0

我复制了我的答案

Windows 中的 fopen 或 CreateFile

由于某种原因而关闭,这让我无法理解......

  1. fopen() 没有定义返回系统错误代码的方法。可能有一种未定义的方式来访问 errno,但这可能与系统错误代码相同,也可能不同。
  2. 另外,我不认为有一种定义的方式来访问真正的系统句柄(类型为 HANDLE),而您可能希望使用它来传递给期望这样一个系统句柄的许多 win64 系统调用之一(例如内存映射IO)
  3. 使用 open() 一个整数表示文件句柄,它不是系统句柄(在 Windows 上)。
  4. fopen() 发生错误时不会抛出异常。为了获得一些 RAII,您需要将其包装到一个类中。
  5. 将 CreateFile() 封装到一个类中并不比将 fopen() 或 open() 封装到一个类中更昂贵。
  6. 使用 C++ 特性(std::ofstream、std::ifstream)写入/读取文件会遇到与 fopen() 相同的问题:
    • 默认情况下它不会抛出错误。为了启用此功能,您需要调用一些方法而不是能够使用一些构造函数参数——这意味着对于 RAII,您需要派生此类(为了将其用作引发错误的成员/基类) .
    • 如果能够从抛出的异常中检索系统错误代码,或者从 what() 返回的消息是否告诉您有关系统错误的任何信息,则未定义。
    • 使用这个流接口没有真正的可插入接口来定义读取或写入的源或目标。重载流接口非常麻烦且容易出错。
  7. 使用类似 C 的编程(注意或忽略返回代码并手动编写清理代码)是许多邪恶的根源(还记得心脏出血吗?)...

结论:

  1. 为 CreateFile()/CloseHandle() 编写资源包装器。资源包装器是一个类,它在构造函数中执行do-action,在析构函数中执行undo-action,并在出错时抛出异常。每个操作系统中都有很多这样的系统调用对,尤其是在 Win64 中。
  2. 编写一个系统错误异常类(在 CreateFile() 失败的情况下用于上述类以及所有其他系统错误)或调查新的 system_exception 类(在 C++0x 中)实际在做什么以及它是否足够了。
  3. 为 ReadFile() 和 WriteFile() 编写一个功能包装器,它将系统错误转换为抛出的系统异常对象...
  4. 可能定义您自己的接口以写入某处并从某处读取,以便您可以实现独立于要读取/写入的源/目标类型的其他内容。
  5. 编写一个允许您缓存从某处读取或写入某处的缓存类也是儿童游戏。当然,缓存类不应该知道也不关心您正在写入/读取的源/目标。

不要害怕这些小任务。您实际上会知道,与调用它的代码相比,您的代码中发生了什么,并且这些小代码片段应该可以忽略不计(以代码行数计)。此外,如果您对所有事情都使用 RAII,那么调用这些实用程序类的代码将比不使用 RAII 并且必须使用两步甚至更多步初始化时要少得多,并且容易出错的可能性要小得多。用其他操作系统的等效实用程序类替换这些实用程序类也是小菜一碟(在 UNIX 上使用 open()/close()/read()/write())。

为了过去的几千年,不要阅读谷歌编程指南!

于 2015-08-03T18:34:59.500 回答