ANSI C标准差点儿被全部的操作系统支持,ANSI C标准提供了完好的I/O函数,使用这些I/O操作我们能够控制程序的输入输出、读写系统磁盘文件。本文记录了用户进程I/O缓冲介绍、文件的读写、文件定位操作等内容。

库函数与系统调用

文件是位于磁盘上的,怎样在执行的程序(进程)中控制文件的读写,通过以下的这张图,我们能够看到应用程序怎样控制系统资源(包含磁盘中的文件)的大概的原理。

操作系统帮助我们管理硬件资源,封装底层实现,以接口的形式(系统调用函数)供上层应用程序调用。直接使用操作系统提供的系统调用函数我们就能够控制文件的读写,可是一般我们在应用程序中不提倡这样做,由于会带来性能上的问题。应用程序调用系统调用函数的时候,操作系统会从用户态转变成内核态,完毕调用后,再从内核态转成用户态(Linux中是通过软中断实现的),而频繁的系统状态切换是须要开销的,会给用户应用程序带来性能上的问题。另外就是可移植性的问题,每一个操作系统向外提供的接口是不尽同样的,假设直接在应用程序中使用系统调用函数,那么程序的可移植性将会非常差。在ANSI
C标准中为我们提供了标准函数(库函数)去操作系统调用函数,库函数是一些可以完毕特定功能的函数,一般由某个标准组织公布,并形成一种公认的标准,所以使用库函数可以屏蔽操作系统间对外接口的差异。

以下是网友总结的库函数和系统调用函数之间的差异

缓冲和非缓冲

对于文件的訪问操作,能够依照是否使用缓冲区,分为缓冲文件操作和非缓冲文件操作

缓冲文件操作:高级文件操作,如第一幅图用户应用程序的左分支,在用户进程空间为打开的文件分配缓冲区。ANSI C标准就是使用的这样的文件操作。本文讨论的正是这样的。

非缓冲文件操作:低级文件操作,如第一幅图用户应用程序的右分支,在用户进程空间不设文件缓冲区。POSIX C标准的I/O就是使用的非缓冲文件操作。

说明:这里所说的缓冲所有指的是用户进程空间的文件缓冲,即使是非缓冲的文件操作,在内核部分也是使用了多级缓冲,而不是直接訪问磁盘(能够參考操作系统的存储器结构)。



文件与文件流

流是一种抽象的数据结构,是ANSI C用来高效的管理打开了的文件信息的,在实际编程中的体现就是struct FILE结构体,在stdio.h头文件里定义,流对象最重要的机制就是缓冲区和格式转换。在Linux系统中系统默觉得每一个进程打开3个文件,相应3个流就是标准输入流、标准输出流、标准错误流。除此之外,须要用到的其它文件须要自己打开和关闭。

文件的I/O操作

依照读/写的对象、能够分为按字符、行、块、格式化等几种读写操作。

(1)按字符读/写文件流

以下的这段程序是使用fgetc和fputc来读取指定文件里的内容到标准输出(显示器),执行时须要指定一个文件

#include<stdio.h>

int main(int argc,char *argv[])
{
FILE *fp=NULL;
char ch;
if(argc<=1)
{
printf("check usage of %s \n",argv[0]);
return -1;
}
if((fp=fopen(argv[1],"r"))==NULL)
{
printf("can not open %s\n",argv[1]);
return -1;
}
while ((ch=fgetc(fp))!=EOF)
fputc(ch,stdout);
fclose(fp);
return 0;
}

执行程序:

(2)按行读/写文件流

以下是一个使用fgets和fputs实现上述功能的程序

#include<stdio.h>
int main(int argc,char *argv[])
{
FILE *fp=NULL;
char str[20];
if((fp=fopen(argv[1],"r"))==NULL) //按仅仅读的形式打开文件
{
printf("can not open!\n");
return -1;
}
fgets(str,sizeof(str),fp); //从打开文件里读取sizeof(str)个字节到str中
fputs(str,stdout); //将str输出到标准输出
fclose(fp); //关闭文件
return 0;
}

(3)依照块读写

以下是使用fread和fwrite来实现的按块读写的程序

#include<stdio.h>
int main(int argc,char *argv[])
{
struct student
{
char name[10];
int number;
};
FILE *fp=NULL;
int i;
struct student boya[2],boyb[2],*pp,*qq;
if((fp=fopen("aa.txt","w+"))==NULL) //以可读写的方式打开文件;若该文件存在则清空,若不存在就创建
{ //打开文件失败
printf("can not open!\n");
return -1;
}
pp=boya;
qq=boyb;
printf(“please input two students‘ name and number:\n");
for (i=0;i<2;i++,pp++)
scanf("%s\%d",pp->name,&pp->number);
pp=boya;
fwrite(pp,sizeof(struct student),2,fp); //将从键盘输入的信息写入到文件流fp中
rewind(fp); //将读写位置定位到文件头
fread(qq,sizeof(struct student),2,fp); //从文件流fp中读两个结构体到qq
printf("name\t\t number\n");
for(i=0;i<2;i++,qq++) //输出qq中的内容
printf("%s\t\t %d\n",qq->name,qq->number);
fclose(fp);
return 0;
}

(4)依照格式化读/写

以下这段程序是使用sprintf和sscanf进行文件读/写操作

#include<stdio.h>

int main()
{
FILE *fp = NULL;
int i = 20;
char ch = 'D';
if((fp=fopen("f2","r+"))==NULL)
{
printf("open file f2 failed.");
return -1;
} fprintf(fp,"%d:%c\n",i,ch); //依照指定格式写文件 int new_i = 0;
char new_ch; rewind(fp); //使读写指针归位 fscanf(fp,"%d:%c\n",&new_i,&new_ch); //依照指定格式读文件 printf("new_i=%d, new_ch=%c\n",new_i,new_ch); fclose(fp); return 0;
}

程序执行结果:

再说缓冲区

能够发现上述4中形式的读写操作,都没有指明缓冲区,可是它们都使用到了位于用户进程空间的文件缓冲区,这是由于,对于随意的流,假设没有指明其缓冲区的类型,系统将指定默认类型的缓冲区。假设用户希望自己指定缓冲区,能够使用setbuf( )或者setvbuf( )函数指定,这两个函数的声明例如以下:

extern  void  setbuf ( 流对象, 缓冲区);

假设将缓冲区设置为NULL,则关闭缓冲区。

extern  int  setvbuf (流对象,缓冲区, 模式,缓冲区大小)

setvbuf比setbuf更加灵活,当中模式可取值有0、1、2,分别表示全缓冲、行缓冲、无缓冲,假设模式是2,那么将会忽视第二和第四个參数。

以下是一个改动缓冲区的程序:

/* Example show usage of setbuf() &setvbuf() */
#include<stdio.h>
#include<error.h>
#include<string.h>
int main( int argc , char ** argv )
{
int i;
FILE * fp;
char msg1[]="hello,wolrd\n";
char msg2[] = "hello\nworld";
char buf[128]; //open a file and set nobuf(used setbuf).and write string to it,check it before close of flush the stream
if(( fp = fopen("no_buf1.txt","w")) == NULL)
{
perror("file open failure!");
return(-1);
}
setbuf(fp,NULL);
memset(buf,'\0',128);
fwrite( msg1 , 7 , 1 , fp );
printf("test setbuf(no buf)!check no_buf1.txt\n");
printf("now buf data is :buf=%s\n",buf); printf("press enter to continue!\n");
getchar();
fclose(fp); //open a file and set nobuf(used setvbuf).and write string to it,check it before close of flush the stream
if(( fp = fopen("no_buf2.txt","w")) == NULL)
{
perror("file open failure!");
return(-1);
}
setvbuf( fp , NULL, _IONBF , 0 );
memset(buf,'\0',128);
fwrite( msg1 , 7 , 1 , fp );
printf("test setvbuf(no buf)!check no_buf2.txt\n"); printf("now buf data is :buf=%s\n",buf); printf("press enter to continue!\n");
getchar();
fclose(fp); //open a file and set line buf(used setvbuf).and write string(include '\n') to it,
//
//check it before close of flush the stream
if(( fp = fopen("l_buf.txt","w")) == NULL)
{
perror("file open failure!");
return(-1);
}
setvbuf( fp , buf , _IOLBF , sizeof(buf) );
memset(buf,'\0',128);
fwrite( msg2 , sizeof(msg2) , 1 , fp );
printf("test setvbuf(line buf)!check l_buf.txt, because line buf ,only data before enter send to file\n"); printf("now buf data is :buf=%s\n",buf);
printf("press enter to continue!\n");
getchar();
fclose(fp); //open a file and set full buf(used setvbuf).and write string to it for 20th time (it is large than the buf)
//check it before close of flush the stream
if(( fp = fopen("f_buf.txt","w")) == NULL){
perror("file open failure!");
return(-1);
}
setvbuf( fp , buf , _IOFBF , sizeof(buf) );
memset(buf,'\0',128);
fwrite( msg2 , sizeof(msg2) , 1 , fp );
printf("test setbuf(full buf)!check f_buf.txt\n"); printf("now buf data is :buf=%s\n",buf);
printf("press enter to continue!\n");
getchar(); fclose(fp); }



其它文件操作

以下介绍一些在文件操作中经常使用的函数

打开、关闭文件操作fopen和fclose

fp = fopen(文件名称,文件操作方式);

文件的操作方式有下面这些

关闭文件使用fclose(文件指针); 或者 fcloseall()函数。

文件流检測

extern  int  feof(流对象)

用于推断流对象是否读到文件尾部,假设是返回1,否则,返回0;

extern  int   ferror(流对象)

用于推断流对象是否出现了错误,若没有错误,则返回0,否则,返回非0。

extern  long  int  ftell(流对象)

返回当前读写位置距离文件开头位置的字节数,若运行失败,返回-1

extern  int  fseek(流对象,偏移距离,基准位置)

基准位置可取值有0、1、2分别表示文件开头、当前位置、文件结尾

将读写位置移到,距离基准位置偏移距离处。若成功,返回0;否则,返回,-1

extern  void  rewind(流对象)

将读写位置重置到文件開始处。

C文件IO的更多相关文章

  1. 标准io与文件io

    A: 代码重复: 语句块1: while(判断) { 语句块2: 语句块1: } 上面可以改写为: while(1) { 语句块1: if(判断) break: 语句块2: } B: 标准IO和文件I ...

  2. 文件IO函数和标准IO库的区别

    摘自 http://blog.chinaunix.net/uid-26565142-id-3051729.html 1,文件IO函数,在Unix中,有如下5个:open,read,write,lsee ...

  3. 转 漫谈linux文件IO

    在Linux 开发中,有几个关系到性能的东西,技术人员非常关注:进程,CPU,MEM,网络IO,磁盘IO.本篇文件打算详细全面,深入浅出.剖析文件IO的细节.从多个角度探索如何提高IO性能.本文尽量用 ...

  4. (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO

    . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...

  5. Java文件IO操作应该抛弃File拥抱Paths和Files

    Java7中文件IO发生了很大的变化,专门引入了很多新的类: import java.nio.file.DirectoryStream;import java.nio.file.FileSystem; ...

  6. Java 文件IO续

    文件IO续 File类    用来将文件和文件夹封装成对象 方便对文件和文件夹的属性信息进行操作    File对象可以作为参数传递给流的构造函数 Demo1 File的构造方法 public cla ...

  7. Java 文件IO

    文件IO Java IO    IO流用来处理设备之间的数据传输 Java对数据的操作是通过流的方式 Java用于操作流的对象都在IO包中    按操作数据分为 字节流和字符流        字符流的 ...

  8. 文件IO和标准IO

    2015.2.26 星期四,阴天 今天的内容主要是文件IO man 手册的分册: man -f open 查看那些分册中有openman 1 -- 普通的命令程序man 2 -- 系统调用man 3 ...

  9. 文件IO操作

    前言 本文介绍使用java进行简单的文件IO操作. 操作步骤 - 读文件 1. 定义一个Scanner对象 2. 调用该对象的input函数族进行文件读取 (参见下面代码) 3. 关闭输入流 说明:其 ...

  10. 文件IO

    在unix世界中视一切为文件,无论最基本的文本文件还是网络设备或是u盘,在内核看来它们的本质都是一样的.大多数文件IO操作只需要用到5个函数:open . read . write . lseek 以 ...

随机推荐

  1. HDU-3502-Huson&#39;s Adventure Island(BFS+如压力DP)

    Problem Description A few days ago, Tom was tired of all the PC-games, so he went back to some old F ...

  2. TCP/IP-协议族----17、应用层简单

    watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaGVrZXdhbmd6aQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQk ...

  3. 新项目架构从零开始(三)------基于简单ESB的服务架构

    这几个月一直在修改架构,所以迟迟没有更新博客. 新的架构是一个基于简单esb的服务架构,主要构成是esb服务注册,wcf服务,MVC项目构成. 首先,我门来看一看解决方案, 1.Common 在Com ...

  4. Memcached FAQ

    这篇FAQ包含了大家普遍关心的问题.非常值得一看. 原文:http://blog.csdn.net/jarfield/archive/2009/07/05/4322953.aspx 最后更新时间 20 ...

  5. 原生javascript学习

    首先在这里要非常感谢无私分享作品的网友们,这些代码片段主要由网友们平时分享的作品代码里面和经常去逛网站然后查看源文件收集到的.把平时网站上常用的一些实用功能代码片段通通收集起来,方便网友们学习使用,利 ...

  6. 构建安全的Xml Web Service系列之如何察看SoapMessage

    原文:构建安全的Xml Web Service系列之如何察看SoapMessage 上一篇文章地址:构建安全的Xml Web Service系列一之初探使用Soap头 (5-22 12:53)     ...

  7. 从jdbc到mybatis

    前面我已经写了几篇文章介绍mybatis的使用方法, 现准备从原理上分析mybatis, 本篇将会解说JDBC演变到mybatis的过程. JDBC查询 使用jdbc查询数据库一般有下面七个步骤: 1 ...

  8. Cntlm安装和配置体验

    对于那些谁使用NTLM验证网络代理环境(即除了需要设置的代理主机和端口还需要提供一个域用户名和密码)供.通过代理上网头疼.这主要是由于非常大的软件不支持NTLM的代理(比方眼下的GIT就不能支持NTL ...

  9. combobox自己主动提示组件加入无选中项清空功能

    这个标题非常绕口,只是这也是想了半天的成果,对不起体育老师了. 标题想表达的是:之前讲过的用combobox实现自己主动提示组件.只是如今规定该组件不能够保存data中不存在的数据. 最初的想法是通过 ...

  10. 【DP专辑】ACM动态规划总结

    转载请注明出处,谢谢.   http://blog.csdn.net/cc_again?viewmode=list          ----------  Accagain  2014年5月15日 ...