我一直在C和C工作,当涉及到文件处理时,我感到困惑 . 让我说出我所知道的事情 .
在C中,我们使用函数:
-
fopen,fclose,fwrite,fread,ftell,fseek,fprintf,fscanf,feof,fileno,fgets,fputs,fgetc,fputc .
-
文件指针的FILE * fp .
-
模式如r,w,a
我知道何时使用这些功能(希望我没有错过任何重要的事情) .
在C中,我们使用函数/运算符:
-
fstream f
-
f.open,f.close,f >>,f <<,f.seekg,f.seekp,f.tellg,f.tellp,f.read,f.write,f.eof .
-
模式如ios :: in,ios :: out,ios :: bin等...
那么(推荐)可以在C中使用C兼容的文件操作吗?哪个更广泛使用,为什么?除了这些我还应该注意什么?
3 回答
有时候现有的代码需要一个或另一个需要与之交互,这可能会影响您的选择,但一般来说,如果C版本没有问题可以解决,那么就不会引入C版本 . 改进包括:
RAII语义,意味着例如
fstream
关闭他们离开范围时管理的文件模式在发生错误时抛出异常的能力,这可以使更清晰的代码专注于典型/成功的处理(请参阅http://en.cppreference.com/w/cpp/io/basic_ios/exceptions for API函数和示例)
类型安全性,使用所涉及的变量类型隐式选择如何执行输入和输出
C风格的I / O有可能发生崩溃:例如
int my_int = 32; printf("%s", my_int);
,其中%s
告诉printf
期望指向ASCIIZ字符缓冲区但是会出现my_int
;首先,传递约定的参数可能意味着int
被不同地传递给const char*
,其次sizeof int
可能不等于sizeof const char*
,最后,即使printf
提取32
作为const char*
充其量它只会从内存地址32开始随机打印垃圾直到它恰巧碰到一个NUL角色 - 这个过程很可能缺乏阅读部分内存的权限,程序也会崩溃 . 现代C编译器有时可以根据提供的参数验证格式字符串,从而降低这种风险 .用户定义类型的可扩展性(即您可以教流如何处理自己的类)
支持根据实际输入动态调整接收字符串的大小,而C函数往往需要硬编码的最大缓冲区大小和用户代码中的循环来组合任意大小的输入
流有时也被批评为:
格式化的详细程度,特别是"io manipulators"设置宽度,精度,基数,填充,与
printf
-style格式字符串相比有时令人困惑的混合操纵器,它们将设置保留在多个I / O操作中,而其他操作符则在每次操作后重置
缺少便利类用于RAII推送/保存以及稍后弹出/恢复操纵器状态
缓慢,正如Ben Voigt的评论和文件here
printf()
/fwrite
样式I / O和C IO流格式之间的性能差异非常依赖于实现 .一些实现(例如,可视化C),在FILE *对象之上构建其IO流,这往往会增加其实现的运行时复杂性 . 但请注意,以这种方式实现库没有特别的限制 .
我个人认为,C I / O的好处如下:
类型安全 .
实施的灵活性 . 可以编写代码以对特定的
ostream
或istream
对象进行特定格式化或输入 . 然后,应用程序可以使用任何类型的派生流对象调用此代码 . 如果我现在需要将针对文件编写和测试的代码应用于套接字,串行端口或其他类型的内部流,则可以创建特定于该类I / O的流实现 . 以这种方式扩展C样式I / O甚至不可能 .语言环境设置的灵活性:在我看来,使用单一全局语言环境的C方法存在严重缺陷 . 我遇到过我调用库代码(DLL)的情况,它改变了代码下面的全局语言环境设置并完全弄乱了我的输出 . C流允许您将任何语言环境设置为流对象 .
这里可以找到一个有趣的关键比较 .
C++ FQA io
不完全礼貌,但让人想到...
Disclaimer
C FQA(这是对C常见问题解答的关键回应)通常被C社区认为是“愚蠢的家伙发出的愚蠢的笑话,甚至不理解C是或想成为什么”(来自FQA)本身) .
这种论证经常被用来点燃(或逃避)C信徒,其他语言信徒或语言无神论者之间的宗教斗争,每个人都以他自己的拙见认为是某种东西优于对方 .
我对这种战斗不感兴趣,我只想激发关于利弊论证的批判性推理 . C FQA - 在这个sens-__ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _这就是我引用它的唯一原因 .
继TonyD评论之后(坦克为他们,我让我明白我的意图需要澄清......),必须注意OP不只是讨论
<<
和>>
(我只是在我的评论中谈到它们只是为了简洁)但是整个功能集构成了C和C的I / O模型 .考虑到这个想法,还要考虑其他“命令式”语言(Java,Python,D ...),你会发现它们比C更符合C模型 . 有时使它甚至类型安全(C模型不是什么,这是它的主要缺点) .
What my point is all about
当C出现在主流(1996年左右)时,
<iostream.h>
库(注意".h":pre-ISO)是一种语言,其中模板尚未完全可用,基本上 no type-safe support for varadic functions (我们必须等到C 11得到他们),但 with type-safe overloaded functions .oveloading
<<
反复重新调整它的第一个参数的想法实际上是一种仅使用二进制函数链接变量参数集的方法,它可以以类型安全的方式重载 . 这个想法延伸到任何"state management function"(如width()
或precision()
)通过操纵器(如setw
)显示为自然结果 . 这一点 - 尽管你可能对FQA作者所做的事情 - 是真实的事实 . 事实上,FQA是我发现的唯一谈论它的网站 .也就是说,多年以后,当D语言被设计为开始提供varadic模板时,
writef
函数被添加到D标准库中,提供类似printf
的语法,但也是完全类型安全的 . (见here)如今C 11也有varadic模板...所以同样的方法可以以同样的方式推出 .
Moral of the story
对于现代编程风格,C和C io模型都显得相同 . C保留速度,C类型安全性和"more flexible abstraction for localization"(但我想知道有多少C程序员在世界上都知道语言环境和方面...) at a runtime-cost (jut track with a debugger the << of a number,through stream ,缓冲区域设置和方面......以及所有相关的虚函数!) .
C模型也很容易扩展到参数消息(参数的顺序取决于它们所在文本的本地化),格式字符串如
@ 1%d @ 2%我允许scrpting像
"text @2%i text @1%d ..."
C模型没有“格式字符串”的概念:参数顺序是固定的,并与文本混合 .
但C 11 varadic模板可用于提供以下支持:
可以提供编译时和运行时语言环境选择
可以提供编译时和运行时参数顺序
可以提供编译时参数类型安全性
...全部使用简单的格式字符串方法 .
是时候标准化新的C i / o模型了吗?