linux基于文件指针的文件读写

1、基于文件指针的文件操作(缓冲)

文件指针:每打开一个文件,则产生一个对应的流(stream)与之结合,然后产生一个 FILE 类型结构体变量和这个流结合在一起,同时返回一个指向该结构体的指针(FILE*),称为文件指针。这个结构体包含了管理该流所需要的所有信息。我们不必去关心这个结构体,只需要知道如何使用 FILE*类型的指针操作文件即可。

缓冲区:输入输出的数据并不是一下子直接到电脑内存和显示器中,输入的数据先暂时存放在键盘缓冲区中,然后程序从该缓冲区中读取数据。输出的数据先暂时存放在输出缓冲区中,然后再把该数据输出到屏幕中。本节介绍的输入输出相关函数都是要用到缓冲区。

linux 的文件和文件描述符:
linux 中对目录和设备的操作都是文件操作,文件分为普通文件,管道文件,目录文件,链接文件和设备文件。
普通文件:也称磁盘文件,并且能够进行随机的数据存储(能够自由 seek 定位到某一个位置);
管道文件:是一个从一端发送数据,另一端接收数据的数据通道;
目录文件:也称为目录文件,它包含了保存在目录中文件列表的简单文件。
设备文件:Linux 下各种硬件设备都是文件,该类型的文件提供了大多数物理设备的接口。它又分为两种类型:
字符型设备和块设备。字符型设备一次只能读出和写入一个字节的数据,包括调制解调器、终端、打印机、声卡
以及鼠标;块设备必须以一定大小的块来读出或者写入数据,块设备包括 CD-ROM、RAM 驱动器和磁盘驱动器
等,一般而言,字符设备用于传输数据,块设备用于存储数据。
套接字文件:在 Linux 中,套接字也可以当作文件来进行处理。


文件的打开和创建

#include <stdio.h> //头文件包含
FILE *fopen(const char *path,const char *mode); //文件名 模式
FILE *fdopen(int filds,const char *mode);
FILE *freopen(const char *path,const char *mode, FILE *stream);
int fclose(FILE *stream);
fopen 以 mode 的方式打开或创建文件,如果成功,将返回一个文件指针,失败则返回 NULL.
fopen 创建的文件的访问权限将以 0666 与当前的 umask 结合来确定。
mode 的可选模式列表

在这里插入图片描述
fdopen 函数用来打开某些不能直接用 fopen 方式打开的文件,比如管道和网络套接字文件。
freopen 打开一个特定的文件(由 path 指定),并将打开后的文件与指定的流(由 fp 指定)关联起来。一般用来
将一个指定的文件打开为一个指定的流:标准输入、标准输出、标准出错。
在 Linux 系统中,mode 里面的’b’(二进制)可以去掉,但是为了保持与其他系统的兼容性,建议不要去掉。ab 和 a+b
为追加模式,在此两种模式下,无论文件读写点定位到何处,在写数据时都将是在文件末尾添加,所以比较适合
于多进程写同一个文件的情况下保证数据的完整性。


文件的读写

#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);
fread 从文件流 stream 中读取 nmemb 个元素,写到 ptr 指向的内存中,每个元素的大小为 size 个字节。
fwrite 从 ptr 指向的内存中读取 nmemb 个元素,写到文件流 stream 中,每个元素 size 个字节。
所有的文件读写函数都从文件的当前读写点开始读写,读写完以后,当前读写点自动往后移动 size*nmemb 个字
节。
2.1.3 格式化读写:
#include <stdio.h>
int printf(const char *format, ...); //相当于 fprintf(stdout,format,…);
int scanf(const char *format,);
int fprintf(FILE *stream, const char *format, ...);
int fscanf(FILE *stream, const char *format,);
int sprintf(char *str, const char *format, ...); // eg: sprintf(buf,”the string is;%s”,str);
int sscanf(char *str, const char *format,);
以 f 开头的将格式化后的字符串写入到文件流 stream 中 。
以 s 开头的将格式化后的字符串写入到字符串 str 中。
2.1.4 单个字符读写:
使用下列函数可以一次读写一个字符 :
#include <stdio.h>
int fgetc(FILE *stream);
int fputc(int c, FILE *stream);
int getc(FILE *stream); 等同于 fgetc(FILE* stream)
int putc(int c, FILE *stream); 等同于 fputc(int c, FILE* stream)
int getchar(void); 等同于 fgetc(stdin);
int putchar(int c); 等同于 fputc(int c, stdout);
getchar 和 putchar 从标准输入输出流中读写数据,其他函数从文件流 stream 中读写数据。
2.1.5 字符串读写:
char *fgets(char *s, int size, FILE *stream);
int fputs(const char *s, FILE *stream);
int puts(const char *s); 等同于 fputs(const char *s, int size, stdout);
char *gets(char *s); 等同于 fgets(const char *s, int size, stdin);
fgets 和 fputs 从文件流 stream 中读写一行数据;
puts 和 gets 从标准输入输出流中读写一行数据。
fgets 可以指定目标缓冲区的大小,所以相对于 gets 安全,但是 fgets 调用时,如果文件中当前行的字符个数
大于 size,则下一次 fgets 调用时,将继续读取该行剩下的字符,fgets 读取一行字符时,保留行尾的换行符。
fputs 不会在行尾自动添加换行符,但是 puts 会在标准输出流中自动添加一换行符。

文件的定位:
文件定位指读取或设置文件当前读写点,所有的通过文件指针读写数据的函数,都是从文件的当前读写点读写数据的。

#include <stdio.h>
int feof(FILE * stream); //通常的用法为 while(!feof(fp))
int fseek(FILE *stream, long offset, int whence);//设置当前读写点到偏移 whence 长度为 offset 处
long ftell(FILE *stream); //用来获得文件流当前的读写位置
void rewind(FILE *stream); //把文件流的读写位置移至文件开头 fseek(fp, 0, SEEK_SET);
feof 判断是否到达文件末尾的下一个(注意到达文件末尾之后还会做一次)
fseek 设置当前读写点到偏移 whence 长度为 offset 处,whence 可以是:
SEEK_SET (文件开头 0)
SEEK_CUR (文件当前位置 1)
SEEK_END (文件末尾 2)
ftell 获取当前的读写点
rewind 将文件当前读写点移动到文件头

标准输入/输出流

在进程一开始运行,就自动打开了三个对应设备的文件,它们是标准输入、输出、错误流,分别用全局文件指针
stdinstdoutstderr 表示,它们都是 FILE *类型。stdin 具有可读属性,缺省情况下是指从键盘的读取输入,stdoutstderr 具有可写属性,缺省情况下是指向屏幕输出数据。
示例:
#include <stdio.h>
#include <unistd.h>
int main()
{
char szBuf[32];
printf("Input string:"); //向屏幕输出一字符串
fgets(szBuf,sizeof(szBuf),stdin);//从键盘读入一行字符串
fprintf(stdout,"The string is:%s",szBuf);//向屏幕输出一行字符串
return 0;
}

看了以上想做几点验证:
1、验证这个缓冲性:

#include <stdio.h>
#include <unistd.h>
int main()
{
	//fprintf(stdout,"hello,work!\n");//第一种情况
	fprintf(stdout,"hello,work!");   //第二种情况
	sleep(5);
	return 0;
}

以上代码如果执行的是:
如果执行第一种情况的语句,直接输出字符串hello,work!,因为这个行字符串后面有\n,表示写入结束,系统会将其从缓冲区写入stdout;第二种情况就等待5秒,程序结束之后才显示hello,work,因为程序语句没有\n,这个字符串一直在缓冲区中,没能将其写入屏幕输出流中,得等程序结束之后系统才会帮它输出到屏幕上。

2、测试一下缓冲区的大小

#include <stdio.h>
#include <unistd.h>
#define LENG 1025
int main()
{
	char a[LENG]={0};
	memset(a,'1',LENG-1);
	a[LENG-1]=0;
	fprintf(stdout,a); //stdout屏幕的显示的文件流
	sleep(5);
	printf("\n-----------------------------\n");
	return 0;
}

当LENG 为1024的时候,程序会等待5秒才会输出出来;当LENG大于1024,1024部分就会先显示出来,剩下不够1024的就等程序结束后才显示出来。说明了我系统的文件流缓冲区是1K

3、不同进程打开一个文件时候是不是共享一个文件句柄?

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
	FILE * kk=0;
	char a[3]={0};
	printf("Parent process id:%d\n",getpid());
	pid_t iRet = fork();
	if(iRet < 0){//出错
		printf("Create child process fail!\n");
	}else if(iRet == 0){//表示子进程
		printf("\n-------child-------------\n");
		kk=fopen("./hallo.txt","rb");
		memset(a,0,3);
		if(kk!=0){
			fread(a,1,2,kk);
			printf("%s\n",a);
			fclose(kk);
		}
	}else{//表示父进程
		sleep(1);
		printf("\n--------parent-----------\n");
		kk=fopen("./hallo.txt","rb");
		memset(a,0,3);
		if(kk!=0){
			fread(a,1,2,kk);
			printf("%s\n",a);
			fclose(kk);
		}
	}
	return 0;
}

文件hallo,txt里面的内容是123456789,得到的结果是:
在这里插入图片描述
说明不同进程虽然打开一个文件,但是他们的文件指针指向的句柄却不一样,因为他们的文件偏移没有共享

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值