Linux流编程

来源:互联网 发布:windows文件夹加密软件 编辑:程序博客网 时间:2024/05/21 14:57

与文件编程相比,基于流的IO方式最大特点就是先对缓冲区进行操作,具有较高的操作效率。流的操作过程与基于文件描述符的I/O操作过程十分类似:对流进行读写、定位操作等,最后关闭流。

在Linux中,对于流的打开就是建立一个缓冲区,将这个缓冲区和对应的文件相关联的过程,Linux提供了fopen、fdopen、freopen等函数来完成相应的操作,调用fclose函数会将流中的数据写入对应的文件中,并且清除整个缓冲区。

/*Name: Copyright: Author: Li Jiansong Date: 08/10/15 08:59Description: 调用fopen打开argv[1]所指向的文件,如果没有改文件则创建,然后关闭这个流 */#include<stdio.h>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也提供了相关的函数。流的缓冲方式有3种:全缓冲,在这种方式下,直到缓冲区被填满,才使用系统调用进行操作,Linux内核中使用宏_IO_FULL_BUF来表示全缓冲;行缓冲,在这种方式下,遇到换行符才使用系统调用进行操作;无缓冲,这种方式下,不进行缓冲,数据会立即读入或者输出到外存文件和设备上。

Linux中的流最终都是需要对应到具体的文件,所以每个流都有对应的文件描述符,可以对流调用fileno函数来获得流对应的文件描述符。对于流的缓冲区设置,如果需要对Linux内核提供的流缓冲状态进行修改,可以调用setbuf、setvbuf、setbuffer、setlinebuf、setlinebuf等系列函数。

/*Name: Copyright: Author: Li Jiansong Date: 08/10/15 08:59Description: 打印3个标准流和一个关联到普通文件的流缓冲状态 */#include<stdio.h>#include<stdlib.h>#if defined(MACOS)#define _IO_UNBUFFERED __SNBF#define _IO_LINE_BUF __SLBF#define _IO_file_flags _flags#define BUFFERSZ(fp) (fp)->_bf._size#else#define BUFFERSZ(fp) ((fp)->_IO_buf_end -(fp)->_IO_buf_base)#endif void pr_stdio(const char*,FILE *);//缓冲输出函数 int main(int argc,char *argv[]){FILE *fp;printf("please enter some str:\n"); if(getchar()==EOF){perror("getchar error\n");}fputs("one line to standard error\n",stderr);pr_stdio("stdin",stdin);pr_stdio("stdout",stdout);pr_stdio("stderr",stderr);perror("fopen error");if(getc(fp)==EOF)perror("getc error");pr_stdio("/etc/motd",fp);exit(0);}void pr_stdio(const char *name,FILE *fp){printf("stream = %s,",name);if(fp->_IO_file_flags & _IO_UNBUFFERED)printf("unbuffered");else if(fp->_IO_file_flags & _IO_LINE_BUF)printf("line buffered");elseprintf("fully buffered");printf(",buffer size = %d\n",BUFFERSZ(fp));}


对流的操作的主要目的就是对流所指定的文件进行读写,对流的读写操作主要有3种:字符读写,每次读写一个字符数据;行读写,当遇到换行符的时候,则将流中换行符之前的内容送到缓冲区中,每次读写一行;块读写,以块为单位进行读写。对于字符读写,可以调用getc、fgetc、getchar等系列函数来完成。对于行读写,可以调用gets、fgets、puts、fputs等系列函数。在读写操作中,如果需要操作的区域多余一个字符或者多余一行,使用字符读写和行读写都比较麻烦,并且在一行数据中包括了NULL字符也会导致行操作的终止,此时可以调用二进制(按块/结构)读写函数,此时可以调用fread、fwrite等系列函数。在关闭流或者完成相应的操作以后应该将缓冲区的数据清空,Linux提供了fflush和_fpurge等函数来完成流的清洗。

/*Name: Copyright: Author: Li Jiansong Date: 08/10/15 08:59Description: 字符读写 */#include<stdio.h>#include<errno.h>int main(int argc,char *argv[]){int c;printf("please enter some str, CTRL+D for stop!\n");while((c=getc(stdin))!=EOF){if(putc(c,stdin)==EOF){perror("output error");}}if(ferror(stdin))perror("input error");return 0;}#include<stdio.h>int main(){char s[80];fputs(fgets(s,80,stdin),stdout);    return 0;}

对于流的定位,有3种方式:使用ftell和fseek函数,必须假设偏移量可以放到一个长整型中,针对这两个函数,Linux还提供了rewind函数用于将偏移量设置到流的起始部分;ftello和fseeko函数,使用了off_t数据类型代替长整型;fgetpos和setpos函数,使用一个抽象数据类型fpos_t来记录文件的位置,该数据类型可以定义为一个文件位置所需要的长度。

#include<stdio.h>int main(){FILE * stream;long offset;fpos_t pos;stream=fopen("/etc/passwd","r");fseek(stream,5,SEEK_SET);printf("offset=%d\n",ftell(stream));rewind(stream);fgetpos(stream,&pos);printf("offset=%d\n",pos);pos=10;fsetpos(stream,&pos);printf("offset = %d\n",ftell(stream));fclose(stream);    return 0;}

此外,Linux内核允许用户建立并使用临时文件。临时文件可以存放计算的中间结果,也可以在关键操作之前用于数据备份。可以使用函数tmpnam、tempnam、tmpfile等来完成该操作。

/*Name: Copyright: Author: Li Jiansong Date: 08/10/15 08:59Description: 利用tmpfile创建并打开一个临时文件,并且写入一行数据,随后将其读出并写入到标准输出 */#include<stdio.h>#include<errno.h>#include<stdlib.h> int main(int argc,char *argv[]){FILE *tempfp;char line[256];tempfp=tmpfile();//获得文件名 if(tempfp==NULL){perror("tmpfile error!\n");return 1;}printf("open a tmp file succeed!\n");fputs("test for tempfile\n",tempfp);rewind(tempfp);if(fgets(line,sizeof(line),tempfp)==NULL){printf("fgets error!\n");return 2;}fputs(line,stdout);return 0;}



1 0
原创粉丝点击