一、在Linux下对文件操作有两种方式:Linux系统调用和ANSI C文件操作。

1、Linux系统调用调用常用于I/O文件操作,系统调用常用的函数有open、close、read、write、lseek、ulink等。

2、 ANSI C文件操作

ANSI C文件操作方法是所有操作系统通用的文件操作方法,它的操作是被缓冲过的被修改的文件并不会立即反应到磁盘中,它在内存中开辟一个“缓冲区”,为程序中的每一个文件操作所使用,当执行读文件的操作时,从磁盘文件中将数据先读入内存“缓冲区“,装满后再从内存“缓冲区”依次读入接收的数据。这种文件操作方式又被称作流式文件操作。ANSI C文件操作常用的函数有fopen、fclose、fread、fwrite、fseek、ftell、rewind、fgetc、fputc、fgets、fputs及remove等

三、下面用两个函数说明Linux系统调用和ANSI C文件操作的区别。

1、由于缓冲区的存在,因此流中的数据与对应文件的数据可能不一致,当系统掉电时,文件若没有及时close(),缓冲区的数据就会丢失,为了同步缓冲区,此时可以调用fflush()函数实现。

fflush()函数需要的头文件:

#include <stdio.h>
函数原型:
int fflush(FILE *stream);
参数说明:

  stream:文件句柄。
返回值:
  成功返回0;
  失败返回EOF。

应用示例:
fflush函数应用示例代码如程序清单1所示。示例程序用来用while死循环模拟掉电状态,打开或创建当前目录下的“./test_2”文件并写入“Hello,world!”字符串。当调用fflush函数后,文件成功写入“Hello,world!”字符串,否则将未写入该字符串。

程序清单1

#include <stdio.h>
#define SyncTestOn 0
int main(void)
{
FILE *fp;
int iCount;
char *str = "Hello world!";
fp = fopen("./test_2", "w"); // 打开文件以获得操作该文件的句柄
iCount = fwrite(str, 12, 1, fp);
printf("%d block(12 bytes per block) read, check it out!\n", iCount);
if (SyncTestOn) {
fflush(fp);
while(1);
} else {
while(1);
}
fclose(fp);
}

说明:SyncTestOn 为0时,程序没有调用fflush(),运行e10时,程序进入while循环,用“Ctrl”+“C”强制退出程序(模拟掉电状态),用cat   test_2命令查看文件,数据此时并没有写入;SyncTestOn 为1时,程序调用fflush(),运行e10,程序进入while,用“Ctrl”+“C”强制退出程序,然后用cat  test_2查看文件,数据此时已经写入。

2、由于缓冲区的存在,为了同步缓冲区,可以调用fflush()实现。但是当掉电时,未调用fflush()时,此时缓冲区的数据仍旧会丢失。而setvbuf()函数可以修改缓冲区的工作模式,也可以解决这一问题。

setvbuf函数需要的头文件:#include <stdio.h>函数原型:int setvbuf(FILE *stream,char *buf,int mode,size_t size);

参数说明:  stream:文件句柄。  buf:如果buf未NULL,由编译器决定如何建立流的缓冲区,否则其应该指向一段大小为size的内存。  mode:指定了缓冲区的类型,_IOFBF(全缓冲),_IOLBJ(行缓冲),_IONBF(无缓冲)。
 size:指定了缓冲区的大小。如果指定一个不带缓冲区的流,则忽略  buf 和 size 参数。返回值:  成功返回0;  失败返回非零值。

应用示例:setvbuf函数应用示例代码如程序清单2所示。

示例程序用来用while死循环模拟掉电状态,打开或创建当前目录下的“./test_3”文件并写入“Hello,world!”字符串。当调用setvbuf函数将缓冲区的类型设置为_IONBF后,文件可以正常写入“Hello,world!”字符串,否则将未写入该字符串。


<pre name="code" class="cpp">#include <stdio.h>
#define SycnTestOn 1
int main(void)
{
FILE *fp;
int iCount;
char *str = "Hello world!";
fp = fopen("./test_3", "w"); // 打开文件以获得操作该文件的句柄
if(Sycn_Test_On){
setvbuf(fp,NULL,_IONBF,0);
}
iCount = fwrite(str, 12, 1, fp);
printf("%d block(12 bytes per block) read, check it out!\n", iCount);
while(1);
fclose(fp);
}


说明:测试方法同fflush()一致;setvbuf()函数如果要设置流的缓冲区,则函数必须在打开文件后立即调用,一旦操作了流,就不能再调用此函数了,否则结果不可预知。非缓冲的文件操作访问方式,每次对文件进行一次读写操作时,都需要使用linux系统调用来处理此操作,执行一次linux系统调用将涉及到CPU状态的切换,即从用户空间切换到内核空间,实现进程上下文的切换,这将损耗一定的CPU时间,频繁的磁盘访问对程序的执行效率会造成较大的影响。

除此以外,setbuf也可以实现setvbuf用法,

需要的头文件:
#include <stdio.h>函数原型:
int setbuf(FILE *stream,char *buf);
参数说明:
  stream:文件句柄。
  buf:参数buf须指向一个长度为BUFSIZ的缓冲区,如果将buf设置为NULL,则
关闭缓冲区。
返回值:
  成功返回0;
  失败返回非零值。

四、通过以上内容,总结Linux系统调用和ANSI C文件操作的区别。

1、 Linux系统调用

Linux系统调用实际上就是指最底层的一个调用,在linux程序设计里面就是底层调用,面向的是硬件。而ANSI C则是库函数调用,是面向的是应用开发的,相当于应用

程序的API(应用程序接口)。我觉得采用这样的方式有以下几个原因:

第一,双缓冲技术的实现;

第二,可移植性的考虑;

第三,底层调用本身的一些性能缺陷(如频繁擦写影响文件存储介质的寿命);

第四,让API也可以有具体分层和专门的应用方向。

Linux系统调用是操作系统相关的,因此一般没有跨操作系统的可移植性。Linux系统调用发生在内核空间,因此如果在用户空间的一般应用程序中使用系统调用来进行文件操作,会有用户空间到内核空间切换的开销。

事实上,即使在用户空间使用ANSI C文件操作,因为文件总是存在于存储介质上,因此不管是读写操作,都是对硬件(存储器)的操作,都必然会引起Linux系统调用。也就是说,ANSI C文件操作实际上是通过系统调用来实现的。例如C库函数fwrite()就是通过write()系统调用来实现的。这样的话,使用库函数也有系统调用的开销,为什么不直接使用系统调用呢?这是因为读写文件通常是大量的数据(这种大量是相对于底层驱动的系统调用所实现的数据操作单位而言),这时,使用ANSI
C文件操作就可以大大减少系统调用的次数。这一结果又缘于缓冲区技术。在用户空间和内核空间,对文件操作都使用了缓冲区,例如用fwrite写文件,都是先将内容写到用户空间缓冲区,当用户空间缓冲区满或者写操作结束时,才将用户缓冲区的内容写到内核缓冲区,同样的道理,当内核缓冲区满或写结束时才将内核缓冲区内容写到文件对应的硬件媒介。

2.4.2  ANSI C文件操作

ANSI C文件操作通常用于应用程序中对一般文件的访问。ANSI C文件操作是系统无关的,因此可移植性好,由于ANSI C文件操作是基于C库的,因此也就不可能用于内核空间的驱动程序中对设备的操作。

Linux系统调用和ANSI C文件操作的区别的更多相关文章

  1. Linux C 下的大文件操作

    这里说的大文件指大小超过4G的文件. 在32位环境下,linux默认打开.读.写超过4G的文件会返回错误.定义如下宏可以突破这个限制,对read/write和fread/fwrite同时有效. 注意它 ...

  2. [Linux]目录x权限对文件操作的影响

    问题 我们常使用linux以下命令 cd 进入目录 ls 列出目录中的文件 或者直接打开目录中的文件 以上操作对于目录权限位的设置来说,是有一定迷惑性的,如表格所示   cd进入该目录 cd进入该目录 ...

  3. linux系统调用、库函数和内核函数关系与区别

    看系统调用,还有库函数,以前一直不明白,总是以为 系统调用跟库函数是一样的,但是今天才知道是不一样的. 库函数也就是我们通常所说的应用编程接口API,它其实就是一个函数定义,比如常见read().wr ...

  4. Linux程序设计 读笔3 文件操作

    一 linux文件结构 二 系统调用和设备驱动程序 三 库函数 四 底层文件访问 五 标准IO库 六 格式化输入输出 七 文件和目录的维护 八 扫描目录 九 错误处理 十

  5. Linux常用命令_(文件操作)

    对文件的操作主要有以下命令: touch.cp.rm.mv.ln.mkdir.rmdir

  6. linux命令(5)文件操作:ls命令、显示文件总个数

    一:ls命令是最常用的linux命令了:下面是ls --help里面的用法 在提示符下输入ls --help ,屏幕会显示该命令的使用格式及参数信息: 先介绍一下ls命令的主要参数: -a 列出目录下 ...

  7. Linux下C语言的文件操作

    代码: #include <stdio.h> #include <string.h> #include <fcntl.h> /*************基本的函数A ...

  8. Linux基础第四课——文件操作

    文件的创建 touch sudo touch 文件1 文件2 文件3 #支持批量创建文件 sudo rm -f 文件1 文件2 文件3 #支持批量创建 也支持批量删除 echo '谁动谁输,对不起我输 ...

  9. linux下c/c++的文件操作

    opendir,readdir,closedir, stat()查询文件状态 open(), O_TRUNC这个Flag会把打开的文件清零... 文件锁:fcntl, F_GETLK , F_SETL ...

随机推荐

  1. 【雕爷学编程】Arduino动手做(54)---大按键点动模块

    37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的.鉴于本人手头积累了一些传感器和模块,依照实践(动手试试)出真知的理念,以学习和交流为目的,这里准备 ...

  2. node的events模块

    events可以说是node实现异步的基石,也是其他几个常用核心模块api的异步方法的原型. var eventEmitter=require('events').EventEmitter; //va ...

  3. 朱刘算法 有向图定根的最小生成树poj3164

    关于为什么不能用Prim求解此类问题,如下 Prim可以看成是维护两个顶点集或者看成维护一颗不断生成的树(感觉前一种说法好一点) 倘若是有向图有三个顶点1.2.3 边的情况如下 1->2:    ...

  4. 手机短号(hdu2081)

    这里字符串的输入用gets_s()函数. #include<stdio.h> using namespace std; int main() { int N; scanf_s(" ...

  5. html5做webAPP界面适配总结

    一.px em rem px像素(Pixel).相对长度单位.像素px是相对于显示器屏幕分辨率而言的. em是相对长度单位.相对于当前对象内文本的字体尺寸.如当前对行内文本的字体尺寸未被人为设置,则相 ...

  6. JavaScript实现栈结构

    参考资料 一.什么是栈(stack)? 1.1.简介 首先我们需要知道数组是一种线性结构,并且可以在数组的任意位置插入和删除数据,而栈(stack)是一种受限的线性结构.以上可能比较难以理解,什么是受 ...

  7. 虚拟机配置JAVA_HOME

    1.cp home/fan-vm2/es/tools/jdk-8u111-linux-x64.tar.gz usr/java2.tar -zxvf jdk-8u111-linux-x64.tar.gz ...

  8. Istio 流量劫持过程

    开篇 Istio 流量劫持的文章其实目前可以在servicemesher社区找到一篇非常详细的文章,可查阅:Istio 中的 Sidecar 注入及透明流量劫持过程详解.特别是博主整理的那张" ...

  9. eatwhatApp开发实战(一)

    开发背景: 当你想用抛硬币来决定事情的时候,那么硬币抛起的瞬间,你就有答案了.一样的,吃啥?eatwhat点开,按钮一点,你就可以知道你中午要吃啥. 话不多说,项目开发走起 ADT点开,New==&g ...

  10. 01 . HAProxy原理使用和配置

    HaProxy简介 HaProxy是什么? HAProxy是一个免费的负载均衡软件,可以运行于大部分主流的Linux操作系统上. HAProxy提供了L4(TCP)和L7(HTTP)两种负载均衡能力, ...