Linux中的读写流

因为使用到了Linux中使用流读写,因此这里进行了部分总结以供自己以后翻阅查看!如果错误,请多多指出!

目录

一、流读写

1、按照字符读

2、按照字符写

3、按照行读写流

4、按照块/结构读写流

5、案例


一、流读写

对流的操作的主要目的是对流所指定的文件进行操作,所以流的读写也是最重要也是最常见的操作,对流的读写操作可以按照操作的缓冲区大小分为三种:

  • 字符读写:每次读写一个字符数据,如果流是带缓存的,则由流I/O函数处理所有缓存。
  • 行读写:每当遇到换行符的时候,则将流中换行符之前的内容送到缓冲区中,即每次读写一行。
  • 块(结构)读写:以块(结构)为单位进行读写。

1、按照字符读

字符读写方式每次从流中读出或写入一个字符的数据,字符读可以调用getc系列函数进行读操作,对其标准调用格式说明如下:

#include <stdio.h>
int fgetc(FILE *stream);
int getc(FILE *stream);
int getchar(void);

函数如果调用成功,则返回即将读取的下一个字符,如果已经到达文件结尾或者出错,则返回EOF(THE END OF THE FILE),其参数是一个指向流的指针stream。

在前两个函数中,参数fp表示所要读入字符的文件,它们的区别是getc可被实现为宏,而 fgetc 不能实现为宏。这意味着:

  • getc 的参数不应当是具有副作用的表达式。
  • 因为 fgetc 一定是个函数,所以可以得到其地址,这就允许将 fgetc 的地址作为一个参数传送给了一个函数。
  • 调用 fgetc 所需时间很可能长于调用 getc ,因为调用函数通常所需的时间长于调用宏,事实上在<stdio.h>头文件中,getc便是以宏定义的形式实现的,其编码具有较高的工作效率。

第三个函数 getchar 只能用来从标准输入流中输入数据,其作用相当于调用以 stdin 为参数的getc函数,即getc(stdin)。

另外,这三个函数以unsigned char 类型转换为 int 的方式返回一下字符,即使最高位为1也不会使返回值为负,这样就可以返回所有可能的字符值,再加上一个已发生错误或已达到文件尾端的指示值。在<stdio.h>中的常数 EOF 被要求是一个负值,其值经常是-1,这就意味着不能将这三个函数的返回值存放在一个字符变量中,以后还要将这些函数的返回值与常数EOF相比较。

2、按照字符写

对应按字符读,Linux内核同样提供了按字符写函数,对其标准调用格式说明如下:

#include <stdio.h>
int fputc(int c, FILE *stream);
int putc(int c, FILE *stream);
int putchar(ing c);

函数调用成功,则返回输出字符c,若出错则为EOF,对其参数说明如下:

  • c 参数:需要输出的字符。
  • stream参数:接收输出的流指针。

与输入函数一样,putchar(c)等同于putc(c, stdout), putc可被实现为宏,而fputc不能实现为宏。

3、按照行读写流

行读写方式每次从流中读出或者写入一行的数据,行读可以使用gets系列函数,对其标准的调用格式说明如下:

#include <stdio.h>
// 行读函数
char *fgets(char *s, int size, FILE *stream);
char *gets(char *s);

// 行写函数
char *fputs(const char *s, FILE *stream);
int puts(const char *s);

 fgets 函数用于从流stream中读出一行数据,并且送到由s指定的缓冲区中,缓冲区大小由size参数说明,函数一直读到遇到下一个换行符或者读完了n-1个字符。如果需要读入行超过了n-1个字符,则只返回一个不完整的行,但是这个缓冲区总是以NULL结尾,下一次读取会继续执行,如果操作成功则返回缓冲区,如果已经到达文件末尾或者出错,则返回NULL。

gets 函数和 fgets函数功能类似,不过fget是从标准输入流读取数据。

note:在实际使用中,并不推荐使用gets函数,这是因为该函数不能指定缓冲区的大小,在实际使用中容易造成缓冲区溢出。

函数fputs 用于将一个以NULL符为终止的字符串去掉NULL后写到指定的流,需要注意的是该函数并不要求每次输出一行,因为其并不要求在NULL符之前必须是换行符,如果成功则返回一个非负值,如果出错则返回EOF。

puts 函数先将一个以NULL符终止的字符串去掉NULL后写入到标准输出中,返回再写一个换行符。

note:虽然puts并不像gets那样容易导致错误,但还是应该尽量避免使用这个函数,因为其涉及第二次写入一个换行符的问题。 

4、按照块/结构读写流

在读写操作中,如果需要操作的区域多于一个字符或者多余一行,使用字符读写和行读写同样比较麻烦,并且如果在一行数据中包括了NULL字符,则会导致行操作的中止,此时可以使用按块/结构(二进制)读写函数。 

对Linux提供的块/结构读写函数fread 和 fwrite 函数的标准调用格式说明如下:

#include <stdio.h>

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

 fread 函数用于执行之间输出操作,其参数ptr是指向读取数据的缓冲区指针,size是读取对象的大小,nmemb表示欲读取的对象个数,fp是指向要读取的流的FILE结构指针,其返回值为读的对象数,如果出错或者到达文件尾端,则此数字可以少于nmemb。在这种情况下,应调用ferror或feof以判断究竟是哪一种情况。

fwrite 函数用于执行之间输入操作,参数ptr是指向存放将要输入数据的缓冲区指针,size是写入对象的大小,nmemb表示欲写入的对象个数,fp是指向要写入的流的FILE结构指针,其返回值为写的对象数,如果返回值少于所要求的nmemb,则出错。

fread 和 fwrite函数有如下两个常见的用法:

  • 读或写一个二进制数组,例如将一个浮点型数组的第2-5个元素写至一个文件上,对其代码结构说明如下:
float data[10];
// 其中,指定size为每个数组元素的长度,nmemb为欲写的元素数
if(fwrite(&data[2], sizeof(float), 4, fp) != 4){
    printf("fwrite error!\n");
}
  • 读或写一个结构,对其代码结构说明如下。

struct{
    short count;
    long total;
    char name[NAME_SIZE]
} item;

// 其中,指定size为结构的长度,nmemb为1(要写的对象数)
if(fwrite(&item,sizeof(item), 1,fp) != 1){
    printf("fwrite error!\n");
}

 将这两个例子结合起来就可以读或写一个结构数组。为了做到这一点,size应当是该结构的sizeof,而nmemb应是数组中的元素数。

note:fread 函数和 fwrite 函数最大的问题是其只能用于读取同一系统上已经写入的数,这是因为在一个系统上写入的数据可能需要在另外一个系统上运行,从而因为结构体偏移量和存储方式等原因导致错误出现。

标准流介绍:在Linux中有三个标准文件,分别为标准输入、标准输出和标准错误输出,Linux操作系统对这三个标准文件预定义了三个标准流,可以通过相应的指针调用,其说明如下:

#define STDIN_FILENO    0    //  标准输入,对应标准流指针 stdin

#define STDOUT_FILENO  1   // 标准输出,对应标准流指针 stdout

#define STDERR_FILENO  2    // 标准错误输出,对应标准流指针 stderr

需要注意的是,这三个标准流都是自动打开和自动关闭的。

5、案例

案例1:使用getc函数和putc函数按照字符对应流进行读写的实例,其从标准输入(stdin)键盘读入用户的输入字符,然后送到标准输出(stdout)显示器显示,其中涉及到了ferror错误处理函数的应用

#include <stdio.h>
int main(int argc, char *argv[]){
    int temp;        //存放I/O函数的返回值
    printf("输入字符,按Ctrl+D停止!\n");    // 输出提示符
    
    // 如果没有接收到EOF则继续执行
    while(temp = getc(stdin) != EOF){
        
        // 判断putc函数是否接收EOF
        if(putc(temp, stdout) == EOF ){
            printf("字符输出发生错误!\n");
            return -1;
        }
    }

    // 判断标准输入是否正确
    if(ferrof(stdin) != 0){
        printf("输入出现错误!\n");   
        return -2;
    }
    return 0;
}

对文件进行链接编译后,进行执行可以看到提示输入字符。在终端中输入字符串后按回车键可以看到对应的字符再次在显示终端被输出,使用Ctrl+D即可退出!

案例二:该案例中调用fopen函数打开一个由argv指定的文件,然后调用getc读取文件的全部内容直到文件末尾,将读出的内容发送至屏幕显示,同时将存放在writebuf缓冲区的字符使用putc写入到该文件中,最后关闭。

// 使用fopen打开指定文件
// 调用getc函数读取数据并显示到屏幕上
// 并将一个字符串写入该文件
// 文件名由argv[1]参数传递

#include <stdio.h>
#include <fcntl.h>
#include <string.h>

int main(int argc, char *argv[]){
	
	int ch;
	int len;
	int i = 0;	// i是用来记录写入数据的长度
	FILE *fp;

	char writebuf[]="Hello! I have read the file!";

	if(argc != 2){
		printf("Please input the current para!\n");
		return -1;
	}

	// 打开要读取的文件
	fp = fopen(*(argv+1), "ab+");

	if(fp == NULL){
		printf("打开文件失败!\n");
		return -2;
	}

	printf("文件%s中的内容为:\n", *(argv+1));

	// 将文件中的数据在屏幕中显示
	while((ch=getc(fp)) != EOF){
		putchar(ch);
	}

	// 将writebuf中的数据写入到文件中
	len = strlen(writebuf);
	while(len > 0 ){
		//if(writebuf[i] != EOF){
			putc(writebuf[i],fp);
			putchar(writebuf[i]);
			len--;
			i++;
		//}
	}
	fclose(fp);
	return 0;
}

参考文献:程国钢, 张玉兰. Linux C编程从基础到实践, 清华大学出版社, 2015. 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值