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.  paip.android环境搭建与开发事例

    paip.android环境搭建与开发事例 好长时间没有玩AndROID了..以前常常做ANDROID的,今天决定在下载一个要做个时间设置器 作者Attilax ,  EMAIL:1466519819 ...

  2. WPF命令參数CommandParameter

    XAML代码例如以下: <Window x:Class="Demo006.MainWindow" xmlns="http://schemas.microsoft.c ...

  3. Code-Based Configuration (EF6 onwards)

    https://msdn.microsoft.com/en-us/data/jj680699#Using

  4. nyoj 117 找到的倒数 【树阵】+【分离】

    这个问题的解决方案是真的很不错!!! 思路:建立一个结构体包括val和id. val就是输入的数,id表示输入的顺序.然后依照val从小到大排序.假设val相等.那么就依照id排序. 假设没有逆序的话 ...

  5. Android使用的开发MediaRecorder录制声音

    至 Android 录制声音的应用,Android提供 MediaRecorder 类别.大约MediaRecorder可以参考一个特定的解释<Android开发之MediaRecorder类具 ...

  6. c#中的属性

    在C#中我们可以很自由的访问共有字段,但有时我们可能需要某字段只能读或者写,或在改变字段值得时候做一些其他事情,显然这些仅仅依靠字段是无法实现的,于是便有了属性. 1.基本用法 c#中的属性由属性作用 ...

  7. NodeJS常用模块介绍

    收集了NodeJS开发中常用的一些模块. MVC框架 - Express Express 是轻量灵活的Nodejs Web应用框架,它可以快速地搭建网站.Express框架建立在Nodejs内置的Ht ...

  8. 8.Eclipse中创建Maven Web项目

     第一步: 创建maven webproject 注意以下一步: 第二步: 继承parent 改动pom.xml文件例如以下 <projectxmlns="http://maven ...

  9. Apple Watch 1.0 开发介绍 1.3 简介 WatchKit App 架构

    WatchKit app和WatchKit extension一起实现了app的界面.当用户在Apple Watch中操作时,WatchKit app从storyboards中选择合适的场景.比如,如 ...

  10. 证明 poj 1014 模优化修剪,部分递归 有错误

    这个问题是存在做.我发现即使是可行的一个问题,但不一定正确. 大部分数据疲软,因为主题. id=1014">poj 1014 Dividing 题目大意:有6堆石头,权重分别为1 2 ...