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的更多相关文章
-
标准io与文件io
A: 代码重复: 语句块1: while(判断) { 语句块2: 语句块1: } 上面可以改写为: while(1) { 语句块1: if(判断) break: 语句块2: } B: 标准IO和文件I ...
-
文件IO函数和标准IO库的区别
摘自 http://blog.chinaunix.net/uid-26565142-id-3051729.html 1,文件IO函数,在Unix中,有如下5个:open,read,write,lsee ...
-
转 漫谈linux文件IO
在Linux 开发中,有几个关系到性能的东西,技术人员非常关注:进程,CPU,MEM,网络IO,磁盘IO.本篇文件打算详细全面,深入浅出.剖析文件IO的细节.从多个角度探索如何提高IO性能.本文尽量用 ...
-
(二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO
. . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...
-
Java文件IO操作应该抛弃File拥抱Paths和Files
Java7中文件IO发生了很大的变化,专门引入了很多新的类: import java.nio.file.DirectoryStream;import java.nio.file.FileSystem; ...
-
Java 文件IO续
文件IO续 File类 用来将文件和文件夹封装成对象 方便对文件和文件夹的属性信息进行操作 File对象可以作为参数传递给流的构造函数 Demo1 File的构造方法 public cla ...
-
Java 文件IO
文件IO Java IO IO流用来处理设备之间的数据传输 Java对数据的操作是通过流的方式 Java用于操作流的对象都在IO包中 按操作数据分为 字节流和字符流 字符流的 ...
-
文件IO和标准IO
2015.2.26 星期四,阴天 今天的内容主要是文件IO man 手册的分册: man -f open 查看那些分册中有openman 1 -- 普通的命令程序man 2 -- 系统调用man 3 ...
-
文件IO操作
前言 本文介绍使用java进行简单的文件IO操作. 操作步骤 - 读文件 1. 定义一个Scanner对象 2. 调用该对象的input函数族进行文件读取 (参见下面代码) 3. 关闭输入流 说明:其 ...
-
文件IO
在unix世界中视一切为文件,无论最基本的文本文件还是网络设备或是u盘,在内核看来它们的本质都是一样的.大多数文件IO操作只需要用到5个函数:open . read . write . lseek 以 ...
随机推荐
-
JAVA 接口与抽象类的区别
abstract class 与interface都是用来定义抽象概念.例如,对于三角形.圆形.矩形这一些具体的概念,形状就是抽象的概念.因为抽象的概念在问题领域没有具体的概念,所以不能够实例化. a ...
-
[IIS]在CMD中IIS的使用
一.打开IIS管理器1,win+r,打开"运行" 2,输入 InetMgr,就打开了IIS管理器 二.IIS其他相关命令iisreset /RESTART 停止后启动 iisres ...
-
如何去掉html中的超链接
$a= preg_replace("/<a[^>]+>/", "", $a); $a= preg_replace("/<\/a ...
-
emWin -- 模拟器系列1 - 如何建立模拟器开发环境
面对如此强大的emWin,大家是否都有跃跃欲试的冲动呢?但是没有硬件可以调试的童鞋,难道只能望洋兴叹?非也.非也.Segger公司早就考虑到了.Segger推出模拟器的目的不仅仅是为了解决没有硬件的烦 ...
-
linux(ubuntu) 搭建java程序运行环境
一:简介 ubuntu 系统的和linux差不多,我们需要在系统上搭建java程序运行环境,需要安装jdk,mysql这两个软件,tomcat是绿色版,直接通过taz -zxvf tomcat 就可以 ...
-
VMware14 安装CentOS7 实现宿主机ping通虚拟机、虚拟机ping通宿主机、虚拟机能上网且能ping通百度
本文旨在通过通过虚拟机VMware14来安装CentOS7 系统,并配置固定IP来实现在Windows系统中使用Linux环境. 本文目录: 0.本机环境 1.VMware14 初始化 1.1.安装V ...
-
tcp keepalive选项
之前一直对tcp keepalive选项理解有误, 以为通过setsockopt函数设置SO_KEEPALIVE和相关参数后该socket则使用设置的keepalive相关参数 否则使用系统默认的:k ...
-
.NET界面控件DevExpress发布v18.2.4|附下载
DevExpress Universal Subscription(又名DevExpress宇宙版或DXperience Universal Suite)是全球使用广泛的.NET用户界面控件套包,De ...
-
dubbo服务telnet命令
转载 https://www.cnblogs.com/feiqihang/p/4387330.html dubbo服务发布之后,我们可以利用telnet命令进行调试.管理.Dubbo2.0.5以上版本 ...
-
MySQL 简单存储过程实现Redis的INCR功能
USE test; DROP PROCEDURE IF EXISTS pro_testincrement; DELIMITER && CREATE PROCEDURE pro_test ...