C文件IO

时间:2022-06-06 00:34:23

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

库函数与系统调用

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

C文件IO

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

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

C文件IO

缓冲和非缓冲

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

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

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

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



文件与文件流

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

文件的I/O操作

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

C文件IO

(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;
}

执行程序:

C文件IO

(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;
}

程序执行结果:

C文件IO

再说缓冲区

能够发现上述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(文件名称,文件操作方式);

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

C文件IO

关闭文件使用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. &lpar;二&rpar; 一起学 Unix 环境高级编程 &lpar;APUE&rpar; 之 文件 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. JAVA 接口与抽象类的区别

    abstract class 与interface都是用来定义抽象概念.例如,对于三角形.圆形.矩形这一些具体的概念,形状就是抽象的概念.因为抽象的概念在问题领域没有具体的概念,所以不能够实例化. a ...

  2. &lbrack;IIS&rsqb;在CMD中IIS的使用

    一.打开IIS管理器1,win+r,打开"运行" 2,输入 InetMgr,就打开了IIS管理器 二.IIS其他相关命令iisreset /RESTART 停止后启动 iisres ...

  3. 如何去掉html中的超链接

    $a= preg_replace("/<a[^>]+>/", "", $a); $a= preg_replace("/<\/a ...

  4. emWin -- 模拟器系列1 - 如何建立模拟器开发环境

    面对如此强大的emWin,大家是否都有跃跃欲试的冲动呢?但是没有硬件可以调试的童鞋,难道只能望洋兴叹?非也.非也.Segger公司早就考虑到了.Segger推出模拟器的目的不仅仅是为了解决没有硬件的烦 ...

  5. linux&lpar;ubuntu&rpar; 搭建java程序运行环境

    一:简介 ubuntu 系统的和linux差不多,我们需要在系统上搭建java程序运行环境,需要安装jdk,mysql这两个软件,tomcat是绿色版,直接通过taz -zxvf tomcat 就可以 ...

  6. VMware14 安装CentOS7 实现宿主机ping通虚拟机、虚拟机ping通宿主机、虚拟机能上网且能ping通百度

    本文旨在通过通过虚拟机VMware14来安装CentOS7 系统,并配置固定IP来实现在Windows系统中使用Linux环境. 本文目录: 0.本机环境 1.VMware14 初始化 1.1.安装V ...

  7. tcp keepalive选项

    之前一直对tcp keepalive选项理解有误, 以为通过setsockopt函数设置SO_KEEPALIVE和相关参数后该socket则使用设置的keepalive相关参数 否则使用系统默认的:k ...

  8. &period;NET界面控件DevExpress发布v18&period;2&period;4&vert;附下载

    DevExpress Universal Subscription(又名DevExpress宇宙版或DXperience Universal Suite)是全球使用广泛的.NET用户界面控件套包,De ...

  9. dubbo服务telnet命令

    转载 https://www.cnblogs.com/feiqihang/p/4387330.html dubbo服务发布之后,我们可以利用telnet命令进行调试.管理.Dubbo2.0.5以上版本 ...

  10. MySQL 简单存储过程实现Redis的INCR功能

    USE test; DROP PROCEDURE IF EXISTS pro_testincrement; DELIMITER && CREATE PROCEDURE pro_test ...