Linux的读写流原理

版权声明:原创作品请标明出处 https://blog.csdn.net/Huangxiang6/article/details/84749839

一.基于流的操作

1.打开流

#include <stdio.h>

FILE *fopen(const char *path, const char*mode);

FILE *fdopen(int fd, const char *mode);

FILE *freopen(const char *path, const char*mode, FILE *stream);

这三个函数的区别是:

  1.  fopen打开一个指定的文件。**以type方式打开filename文件并返回该文件的指针** 
    
  2.  fropen在一个指定的流上打开一个指定的文件,如若该流已经打开,则先关闭该流。如若该流已经定向,则fopen清除该定向。此函数一般用于将一直指定的文件打开为一个预定义的流:标准输入、标准输出或标准错误。
    
  3.  fdopen获取一个现有的文件描述符,并使一个标准的I/O流与该描述符相结合。此函数常用于由创建管道和网络通信函数返回的描述符。因为这些特殊类型的文件不能用标准I/Ofopen函数打开,所有我们必须先调用设备专用函数以获得一个文件描述符,然后用fopen使一个标准I/O与该描述符相关联。
    

其中的mode参数可以用是以下15种不同的值:
r或rb: 为读打开

w或wb: 把文件截短至0长,或为写而创建

a或ab: 添加;为在文件写打开,或为写打开

r+或r+b或rb+: 为读和写打开

w+或w+b或wb+: 把文件截短至0,或为读和写打开

a+或a+b或ab+: 为在文件尾端读和写而打开或创建

注意:

1.凡用“r”打开一个文件时,该文件必须已经存在,且只能从该文件读出。

2.用“w”打开的文件只能向该文件写入。若打开的文件不存在,则以指定的文件名建立该文件,若打开的文件已经存在,则将该文件删去,重建一个新文件。若以写或读写方式打开一个已存在的文件时将清除原来文件的内容,希望写入的字符以文件末开始存放,必须以追加方式打开文件。

3.若要向一个已存在的文件追加新的信息,只能用“a”方式打开文件。但此时该文件必须是存在的,否则将会出错。

在打开一个文件时,如果出错,fopen将返回一个空指针值NULL。在程序中可以用这一信息来判别是否完成打开文件的工作,并作相应的处理。 常用以下程序段打开文件:

if((fp=fopen("c:\hik","rb")==NULL)
{
      printf("error on open c:\hzk16 file!");
      getch();
      exit(1);
}

如果返回的指针为空,表示不能打开C盘根目录下的hik文件,则给出提示信息“error on open c: \hik file!”,下一行getch()的功能是从键盘输入一个字符,但不在屏幕上显示。在这里,该行的作用是等待,只有当用户从键盘敲任一键时,程序才继续执行, 因此用户可利用这个等待时间阅读出错提示。敲键后执行exit(1)退出程序。

2.关闭流

#include <stdio.h>
int fclose(FILE *fp);    //fp是指向FILE结构的指针变量

fclose函数

头文件:stdio.h

功 能:关闭一个流

用 法:int fclose(FILE *stream);

返回值:成功返回0,不成功返回EOF(-1)

在文件被关闭之前,冲洗缓冲区中的输出数据。如果标准I/O库已经为该流自动分配了一个缓冲区,则释放缓冲区。

​ 与文件编程相比,基于流的IO方式最大特点就是先对缓冲区进行操作,具有较高的操作效率。流的操作过程与基于文件描述符的I/O操作过程十分类似:对流进行读写、定位操作等,最后关闭流。在Linux中,对于流的打开就是建立一个缓冲区,将这个缓冲区和对应的文件相关联的过程,Linux提供了fopen、fdopen、freopen等函数来完成相应的操作,调用fclose函数会将流中的数据写入对应的文件中,并且清除整个缓冲区。

#include<stdio.h>
/*
*argc是命令行总的参数个数,argv[]是argc个参数,其中第0个参数是程序的全名,以后的参数命令行后面跟的用户*输入的参数
*/
int main(int argc,char *argv[])			
{
	FILE *fp;
	int iflag;
	if(argc<=1)
	{
		printf("usage: %s filename\n",argv[0]);
		return 1;
	}
	fp=fopen(argv[1],"a+b");
	if(fp==NULL)
	{
		printf("open file %s failed!\n",argv[1]);
		return 2;
	}
	printf("open file %s succeed!\n",argv[1]);
	iflag=fclose(fp);
	if(iflag==0)
	{
		printf("close file %s succeed!\n",argv[1]);
		return 0;
	}
	else{
		printf("close file %s failed!\n",argv[1]);
		return 3;
	}
}

在linux中测试函数输出:

在这里插入图片描述

UNIX系统中shell把文件描述符0与标准输入关联;换成符号常量就是STDIN_FILENO 提高可读性

​ 文件描述符1与标准输出关联;换成符号常量就是STDOUT_FILENO

​ 文件描述符2余标准出错关联;换成符号常量就是STDERR_FILENO

符号常量定义在头文件<unistd.h>中。

3.读写流

linux内核相应一个块设备文件读写的层次结构(摘自ULK3)

在这里插入图片描述

字符为单位读写数据

每次读写一个字符数据的I/O方式称为每次一个字符的I/O。Linux下使用fgetc函数获得一个字符,其函数原型如下:

3.1fgetc函数

功 能:从fp所指向的文件中读取字符

用 法:int fgetc(FILE *fp);

返回值:返回文件fp所指向的文件中的字符值(EOF为文件尾)

补 充:

1.调用该函数时,文件使用方式必须是以读或读写方式打开的。

2.在文件内部有一个位置指针,用来指向文件的当前读写

    #include<stdio.h>
             int fgetc(FILE *fp);

函数如果执行成功则返回该字符的ASCLL值,如果执行失败,则返回EOF。Linux环境下使用fputc函数输出一个字符数据,函数原型如下:

3.2fputc函数

功能:将字符(ch的值)输出到fp所指向的文件中去。

用法:int futc(int ch,FILE *fp);

返回值:写入成功返回写入字符ch

不成功返回EOF

#include<stdio.h>
	int fputc(int c,FILE*fp)

第一个参数表示想要输出的字符的ASCLL值(源),第二个参数表示想要输出的文件流(目的地)

#include <stdio.h>
int main()
{
	FILE *fp;
    char ch,filename[20];
	printf("Please input your filename:");
	scanf("%s",filename);
    if(!(fp=fopen(filename,"w")))
	{
		printf("Can not open %s\n",filename);
	}
	else
	{
		printf("Please input the sentences you write:");
		ch=getchar();
		ch=getchar();
        while(ch!=EOF)
		{
			fputc(ch,fp);
			ch=getchar();
		}
		fclose(fp);
	}
	    if(!(fp=fopen(filename,"r")))
	{
		printf("Can not open %s\n",filename);
	}
	else
	{
		printf("The content of %s is:",filename);
        while(!feof(fp))
		{
			ch=fgetc(fp);
			putchar(ch);
		}
		printf("\n");
		fclose(fp);
	}
	return 0;
}


为单位读写数据

当输入内容遇到\n时则将流中\n之前的内容送到缓冲区中的I/O方式称为每一次行的I/O。Linux使用下列函数提供一次读入一行的功能。

#include<stdio.h>
	char*fgets(char *restrict buf,int n,FILE*restrict fp);
	char*gets(char*);

​ fgets函数的第一个参数表示存放读入的缓冲区,第二个参数n表示读入的字符个数,此参数的最大值不能超过缓冲区的长度。fgets函数一直读,直到遇到\n为止,如果在n-1个字符內未遇到换行符,则只读入n-1个字符。最后一个字符用于存储字符串结束标志\0.需要注意的是fgets函数会将‘\n’换行符也读进缓冲区中,因此缓冲区的实际有效内容应该是缓冲区实际字节数(不包括‘\0’)减1.fgets函数的第三个参数是需要读入的流对象。

​ fgets函数的换回值有以下两种情况:1,成功读取一行,返回缓冲区的首地址。2,读取出错或者文件已经到达结尾则返回NULL。gets函数和fgets函数类似,该函数从标准输入流中读取一行并将其存入一个缓冲区,并不将‘\n’读进缓冲区中。gets函数的返回值和fgets相同。

​ Linux 环境下用fputs函数和puts函数实现输出一行字符串,其函数原型如下:

#include<stdio.h>
	int fputs(const char*restrict str,FILE *restrict fp);
	int puts(const char*str);

3.3 fgets函数

功 能:从fp所指向的文件(stdin特殊文件)中读取长度为n的字符串保存到string中

**用 法:char *fgets(char string, int n, FILE fp); n表示从文件中读出的字符串不超过 n-1个字符。在读入的

​ 最后一个字符后加上串结束标志’/0’ 。

返回值:成功,返回string

失败,返回NULL

3.4 fputs函数

功 能:将字符串string写入fp所指向的文件中。

*用 法:int fputs(char *string, FILE fp);

返回值:输入成功,返回值0

输入失败,返回EOF

#include <stdio.h>
#define LEN 100
int main()
{
	FILE *fp;				//声明fp是指针,指向FILE类型的对象
    char ch,string[LEN],filename[20],string1[LEN];
 
	printf("Please input your filename:");
	scanf("%s",filename);
 
    if(!(fp=fopen(filename,"w")))
	{
		printf("Can not open %s\n",filename);
	}
	else
	{
		printf("Please input the sentences you write:");
		ch=getchar();
		fgets(string,LEN,stdin);
        if(!fputs(string,fp))
			printf("写入成功\n");
		else
			printf("写入失败\n");
		fclose(fp);
	}
 
	    if(!(fp=fopen(filename,"r")))
	{
		printf("Can not open %s\n",filename);
	}
	else
	{
		printf("The content of %s is:",filename);
        fgets(string1,LEN,fp);
		printf("%s\n",string1);
		fclose(fp);
	}
	return 0;
}


在这里插入图片描述

fputs函数的第一个参数表示存放输出内容的缓冲区,第二个参数表示要输出的文件。如果执行成功则返回输出的字节数,失败返回-1。puts函数用与向标准输出输出一行字符串,其参数和fputs函数的第一个参数相同,如果成功输出,则返回输出的字节数,失败则返回-1,值得注意的是,虽然gets函数不读入\n,但是puts函数却输出\n。fputs和puts函数都不输出字符串的结束符‘\0’。对于I/O来说,fputs函数和fgets函数的搭配是安全又可靠的。

3.5 fwrite函数

**功 能:**从ptr指向的地方读取n个size大小的数据写入fp指向的文件中

*用 法:int fwrite(void *ptr, int size, int n, FILE fp);

返回值:返回写入文件的实际个数

参数说明:ptr:输出数据的地址(首地址)其余同上

注意:这个函数以二进制形式对文件进行操作,不局限于文本文件

3.6 fread函数

功 能:从fp指向的文件中读取n个size大小的数据写入ptr指向的地方

用 法:int fread(void *ptr, int size, int n, FILE *fp);

返回值:成功,返回读取元素个数

​ 不成功,返回0

参数说明:

ptr:读入数据的存放地址(首地址)

size:要读写的字节数

n:要进行读写多少个size字节的数据项

3.7 fscanf函数

功 能:从磁盘文件中按格式读入字符

用 法:int fscanf(FILE *fp, char *format,[argument…]);

示 例:fscanf(fp,"%d,%f",&i,&t);

**返回值:**成功返回读入的参数的个数

​ 失败返回EOF(-1)

注 意:fscanf遇到空格和换行时结束,注意空格时也结束。

3.8 fprintf函数

功 能:从磁盘文件中按格式输出字符

*用 法:int fprintf(FILE *fp, char format,[argument…]);

示 例:fprintf(fp,"%d,%6.2f",i,t);

返回值:成功返回输出的字符数

失败时返回一个负值.

二.系统调用

1.open系统调用

​ 系统调用open的作用是打开一个文件,并返回这个文件的描述符。open建立了一条到文件或设备的访问路径。如果操作成功,它将返回一个文件描述符,read和write等系统调用使用该文件描述符对文件或设备进行操作。这个文件描述符是唯一的,他不会和任何其他运行中的进程共享。如果两个程序同时打开一个文件,会得到两个不同的问价描述符。如果同时对两个文件进行操作,他们各自操作,互补影响,彼此相互覆盖(后写入的覆盖先写入的)为了防止文件按读写冲突,可以使用文件锁的功能。

Linux中open的函数原型有两个:

int open(const char *path, int oflags);

int open(const char *path, int oflags, mode_t mode );

参数说明:

path:准备打开的文件或设备名字。

oflags:指出要打开文件的访问模式。

2.close系统调用

close系统调用用于“关闭”一个文件,close调用终止一个文件描述符fildes以其文件之间的关联。文件描述符被释放,并能够重新使用。close成功返回1,出错返回-1.

#include<unistd.h>
	int close(int fildes);

2.write系统调用

write,就是把缓冲区的数据写入文件中。这里的文件是指广泛意义的文件,比如写入磁盘、写入打印机等等。

Linux 中write()的函数原型:

size_t write(int fildes, const void *buf, size_t nbytes);

参数说明:

fildes:文件描述符,标识了要写入的目标文件。例如:fildes的值为1,就像标准输出写数据,也就是在显示屏上显示数据;如果为 2 ,则想标注错误写数据。

*buf:待写入的文件,是一个字符串指针。

nbytes:要写入的字符数。

函数返回值:size_t 返回成功写入文件的字符数。需要指出的是,write可能会报告说他写入的字节比你所要求的少。这并不一定是个错误。在程序中,你需要检查

error已发现错误,然后再次调用write写入剩余的数据。

3.read系统调用

系统调用read是从文件中读出数据。要读取的文件用文件描述符标识,数据读入一个事先定义好的缓冲区。他返回实际读入的字节数。

Linux中read的函数原型:

size_t read(int fildes, void *buf, size_t nbytes);

参数说明:

fildes:文件描述符,标识要读取的文件。如果为0,则从标准输入读数据。类似于scanf()的功能。

*buf:缓冲区,用来存储读入的数据。

nbytes:要读取的字符数。

返回值:size_t返回成功读取的字符数,它可能会小于请求的字节数。

参考此篇:https://blog.csdn.net/wait_for_taht_day5/article/details/50700471#

猜你喜欢

转载自blog.csdn.net/Huangxiang6/article/details/84749839
今日推荐