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. WPF 3D:使用GeometryModel3D的BackMaterial

    原文 WPF 3D:使用GeometryModel3D的BackMaterial 使用BackMaterial,我们可以定义3D物体的内部材质(或者说是背面),比如,我们定义一个四方体容器,外面现实的 ...

  2. c# 获取某个对象的[公有属性]的名称,类型,值

    /// <summary> /// 获取某个对象的[公有属性]的名称,类型,值 /// </summary> /// <typeparam name="T&qu ...

  3. 使用 WPF 创建单实例应用程序

    一个简单的例子就是大家在使用很多应用程序,例如在使用Microsoft Word 时会遇到一种情况,不管你打开多少个文档,系统一次只能加载一个winword.exe 实例.当打开新文档时,文档在新窗口 ...

  4. Godaddy Drupal Update

    Godaddy对Drupal默认安装仅仅支持到7.22,眼下Drupal已经升级到7.28,安装完Drupal 7.22后,仅仅能手工升级. 安装Drupal在:https://hostingconn ...

  5. perl操作sqlserver实现BCP

    #!C:\Perl64\bin #由BCP备份和恢复SQLSERVER指定表 use 5.014; #加载用户和password型材 my $username ; my $passwd; ##得到us ...

  6. Directx11学习笔记【五】 基本的数学知识----向量篇

    本文参考dx11龙书 Chapter1 vector algebra(向量代数) 要想学好游戏编程,扎实的数学知识是尤为重要的,下面将对dx11龙书中有关向量的数学知识做一下总结. 在数学中,几何向量 ...

  7. hdu1004----用java链表实现

    Let the Balloon Rise Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Oth ...

  8. HDU 4686 Arc of Dream(递归矩阵加速)

    标题效果:你就是给你一程了两个递推公式公式,第一个让你找到n结果项目. 注意需要占用该公式的复发和再构造矩阵. Arc of Dream Time Limit: 2000/2000 MS (Java/ ...

  9. configure.ac:20: error: Autoconf version 2.65 or higher is required

    安装thrift例如,下面的问题出现: configure.ac:20: error: Autoconf version 2.65 or higher is required wget http:// ...

  10. Android源代码学习之六——ActivityManager框架解析

    ActivityManager在操作系统中有关键的数据,本文利用操作系统源代码,逐步理清ActivityManager的框架,并从静态类结构图和动态序列图两个角度分别进行剖析,从而帮助开发者加强对系统 ...