文件的输入和输出操作笔记

25 篇文章 0 订阅
16 篇文章 0 订阅

文件I/O操作

文件描述符:

在Linux中,每打开一个磁盘文件,都会在内核中建立一个文件表项,文件表项中储存着文件的状态信息,储存文件内容的缓冲区和当前文件的读写位置。打开几次就会创建几个这样的文件表项,读写该文件,只会修改该文件表项的文件读写位置。这几个文件表项储存在一个文件表数组tablle[]中。这个文件表的下表就被称为文件描述符。通过文件描述符就可以访问到这个磁盘。

数据流:

从数据操作方式来说,Linux中的文件都可以看做数据流。在对文件进行操作前,必须调用f标准I/O库函数fopen()将数据流打开,打开后才可以操作。

标准I/O库函数是C语言中所持有的用于高级接口的函数,存在stdio.h头文件中,这些用于数据流的I/O操作函数还适用于其他系统,移植性好。

要对数据流近读写操作,需要标准I/O库函数和FILE类型的文件指针。指针是打开数据流时返回的指针,用指针来表示要操作的数据流。

有3中数据流不需要特定的函数打开操作,分别是标准输入、标准输出、标准错误输出。

对数据流操作完后,需要关闭,调用fclose()函数。该函数在关闭数据流之前,会 清空在操作过程中分配的缓冲区并保存数据信息。

基于文件描述符的I/O操作

文件的打开与关闭

open()函数

可以打开或者创建一个文件(包括设备文件)

#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int open(const char *pathname,int flags);
int open(const char *pathname,int flags,mode_t mode);
int creat(cconst char *pathname,mode_t mode);

open()函数和create()函数调用成功,会返回新分配的文件描述符;失败,返回-1,并设置适当的errno值。

pathname:文件的路径名称

flags:文件的打开方式的宏定义

mode: 文件的访问权限设置

文件权限由open()函数的mode参数和当前进程的umask掩码共同决定,umask掩码是系统默认的值,可以在终端下输入umask命令查询。

close()函数

用于关闭一个已打开的文件

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

调用成功,返回0,失败,返回-1,并设置适当的errno值。

fd:要关闭的文件描述符

 

文件的读写操作

read()函数

用于从打开的文件(包括设备文件)中读取数据

#include<unistd.h>
ssize_t read(int fd,void *buf,size_t count);

fd:要读写的文件的文件描述符

buf:读取的数据存放在buf指针所指的缓冲区

count: 读取的数据的字节数

读取文件数据时,文件的当前读写位置会往后移。这个读写位置与C标准I/O库的读写位置而可能不同,这边的是记在内核中,二C标准I/O库时的读写位置时用户空间I/O缓冲区中的位置。

调用成功,返回读取的字节数;失败返回-1,并设置适当的errno值。

返回字节数可能会小于参数count值。

write()函数

用于向打开的设备或文件中写入数据

#include<unistd.h>
ssize_t write(int fd,const void *buf,size_t count);

 fd:要写入数据的文件的文件描述符

buf:写入数据在buf指针所指的缓冲区

count:写入的数据的字节数

调用成功,返回写入的字节数;失败,返回-1,并设置适当的errno值。

当向常规文件吸入数据,返回时count字节数;当向终端设备或者网络写入数据,返回值不一定是写入的字节数。

文件的定位

lseek()函数

移动当前读写位置

#include<sys/types.h>
#include<unistd.h>
off_t lseek(int fildes,off_t offset,int whence);

fildes:文件描述符

offset:偏移量

whence:代表用于偏移时的相对位置

whence取值:

  • SEEK_SET:从文件的开头位置计算偏移量
  • SEEK_CUR:从当前的位置计算偏移量
  • SEEK_END:从文件的末尾计算偏移量

偏移量可以超过文件末尾,对文件进行延迟()使用"\0"填充

调用成功返回新的偏移量;失败返回-1,并设置适当的errno值

例:

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
int main()
{
	char *path="test.c";			/*进行操作的文件路径*/
	int fd;
	char buf[40],buf2[]="hello mrcff";			/*自定义读写用的缓冲区*/
	int n,i;
	if((fd=open(path,O_RDWR))<0)				/*打开文件*/
	{
		perror("open file failed!");
		return 1;
	}
	else
		printf("open file successful!\n");
	if((n=read(fd,buf,20))<0)				/*读取文件中的数据*/
	{
		perror("read failed!");
		return 1;
	}
	else
	{	printf("output read data:\n");
		printf("%s\n",buf);				/*将读取的数据输出到终端控制台*/
	}
	if((i=lseek(fd,11,SEEK_SET))<0)				/*定位到从文件开头处到第11个字节处*/
	{
		perror("lseek  error!");
		return 1;
	}
	else
	{
		if(write(fd,buf2,11)<0)				/*向文件中写入数据*/
		{
			perror("write error!");
			return 1;
		}
		else
		{
			printf("write successful!\n");			
	
		}
	}
	close(fd);						/*关闭文件的同时保存了对文件的改动*/
	
	if((fd=open(path,O_RDWR))<0)				/*打开文件*/
	{
		perror("open file failed!");
		return 1;
	}	
	if((n=read(fd,buf,40))<0)				/*读取数据*/
	{
		perror("read 2 failed!");
		return 1;
	}
	else
	{	
		printf("read the changed data:\n");		
		printf("%s\n",buf);				/*将数据输出到终端*/
	}
	if(close(fd)<0)						/*关闭文件*/
	{
		perror("close failed!");
		return 1;
	}
	else
		printf("good bye!\n");
return 0;
}

 

基于数据流的I/O操作

基于数据流的I/O操作是通过一个FILE类型的文件指针实现对文件的访问的。在FILE结构体类型中储存着许多关于流操作所需要的信息。这些函数都是存放在stdio.h头文件中声明的。

文件的打开与关闭

fopen()函数

#cinclude<stdio.h>
FILE *fopen(const char *path,const char *mode);

path:打开的文件的路径名

mode: 文件的打开方式

调用成功,返回文件指针;失败返回NULL,并设置适当的errno值。

mode参数不介绍了,具体百度,自己搜。

fclose()函数

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

fp:要关闭的文件的指针。

调用成功返回-;失败返回EOF(-1)并设置适当的errno值。 

字符输入/输出

fgetc()函数

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

参数略

从指定文件中读取一个字节

 调用成功,返回读到的字节;失败或这读到文件末尾,返回EOF(-1)

fputc()函数

#include<stdio.h>
int foutc(int c,FILE  *stream);

参数略

把字符c写入stream指针所指的文件中。

调用成功返回写入的字节,否则返回EOF(-1)。 

例:

多次调用fputc()函数向文件test.c中写入数组a中的戒子,然后通过多次调用fgetc()函数获取文件中的数据存放在字符变量ch中,最终显示到终端屏幕上。

#include<stdio.h>

int main()
{
	FILE *fp;
	int i;
	char *path="test.c";
	char a[]={'h','e','l','l','o',' ','m','r'};
	char ch;
	fp=fopen(path,"w");/*以只写打开文件*/
	if(fp)					/*判断是否成功打开文件*/
	{
		
	for(i=0;i<5;i++)
	{

		if(fputc(a[i],fp)==EOF)/*向文件中循环写入a数组中的内容*/
		{
			perror("write error!");
			return 1;
		}
	}
	
		printf("write successful!\n");
        }
	else
	{
		printf("open error!\n");
		return 1;
	}		
	fclose(fp);				/*关闭文件*/
	if((fp=fopen("test.c","r"))==NULL)/*以只读的形式打开文件*/
	{
		perror("open error!");
		return 1;
	}
	printf("output data in the test.c\n");
	for(i=0;i<5;i++)
	{
		if((ch=fgetc(fp))==EOF)/*循环方式获取文件中的5个字节*/
		{
			perror("fgetc error!");
			return 1;
		}
		else
		{
			printf("%c",ch);/*输出字符*/
		}
	}
	printf("\nget successful!\nplease examine test.c...\n");
	fclose(fp);/*关闭文件*/
return 0;

}

字符串输入/输出

fgets()函数

#include<stdio.h>
char *fgets(char *s,int size,FILE *stream);

 实现了从参数stream所指的文件中读取一串小于参数size所代表字节数的字符串,并将字符串储存到s所指的缓冲区中。

函数调用成功,返回内容为s所指的缓冲区部分的指针;失败(的渠道文件末尾或者出错)返回NULL。

在size字节范围内没有读到“\n”结束符,增加一个"\0"组成字符串储存到缓冲区中;文件剩余的字符在下次调用fgets()函数再读取。

fgets()函数只用于读取文本文件,不推荐读二进制("\n"在函数中为结束符,"\0"是普通字符,无法判断这个是自动增加的还是文件读出来的)

fputs()函数

#include<stdio.h>
int fputs(const char *s,FILE *stream);

向stram指针所指的文件中写入s缓冲区的字符串。

调用成功,返回一个非负整数;失败,返回EOF。(-1)

数据块输入/输出

fread()函数和fwrite()函数

#include<stdio.h>
size_t  fread(void *ptr,size_t size,size_t nmemb,FILE *stream);
size_t  fwrite(const void *ptr,sizt_t size,size_t nmemb,FILE *stream);

size:一个数据块大小

nmemb:要读或些多少条这样的数据块

stream:文件指针

ptr:指针所指的内存空间

调用成功,返回读或写的记录,记录数等于nmemb;失败(出错或读到文件末尾),可能返回0

格式化输入/输出

格式化输出函数

#include<stdio.h>
int printf(const char *format,...);
int fprintf(FILE *stream,const char *format,...);
int sprintf(char *str,const char *format,...);
int snprintf(char *str,size_t size,const char *format,...);

调用成功,返回格式化输出的字节数(不包括字符串结尾"\0");失败,返回一个负值。 

printf()略

fprintf()函数是向文件中输出字符串

snprintf()和sprintf()函数是向str所代表的字符串中输出数据,size为缓冲区的大小(防止溢出)

格式化输入函数

#include<stdio.h>
int scanf(const char *format,...);
int fscanf(FILE *stream,const char *format,...);
int sscanf(const char *str,const char *format,...);

fscanf()函数从指定的文件获取字符

sscanf()函数从哪个指定而字符串str中获取字符

调用成功,返回成功匹配和赋值的参数的个数,成功匹配的参数可能少提供给的赋值参数。返回0表示一个都不匹配;失败,返回EOF,并设置errno值。

操作读写位置的函数

fseek()函数

#include<stdio.h>
int fseek(FILE *stream,long offset,int whence);

 一般用于二进制文件。

whence表四从何处开始计算位移量。SEEK_SET(0,文件首),SEEK_CUR(1,文件当前位置),SEEK_END(2,文件结尾)

调用成功,返回0;失败返回-1,并设置适当的errno值。

例:

在一个文件的第二个字节处插入字符m

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
	FILE* fp;
	if ( (fp = fopen("file.c","r+")) == NULL) /*以读写的方式打开一个已存在的文件file.c*/
	{
		perror("Open file textfile");
		exit(1);
	}
	if (fseek(fp, 2, SEEK_SET) != 0)/*将读写位置定位在从文件开头处计算的第2个字节处*/ 
	{
		perror("Seek file textfile");
		exit(1);
	}
	fputc('m', fp);			/*在此处插入字符m*/
	fclose(fp);			/*关闭文件*/
	return 0;
}

ftell()函数

#include<stdio.h>
long ftell(FILE *stream);

 得到stream指定的流文件中的当前位置。

调用成功,返回当前的位移量;失败返回-1并设置适当的errno值

rewind()函数

#include<stdio.h>
void rewind(FILE *stream);

 使位置指针重新返回文件的开头

例:

#include<stdio.h>
#include<stdlib.h>
main()
{
    FILE *fp;
    char ch,filename[50];
    printf("请输入文件路径及名称:\n");
    scanf("%s",filename);							/*输入文件名*/
    if((fp=fopen(filename,"r"))==NULL) 				/*以只读方式打开该文件*/
    {
        printf("不能打开的文件!\n");
        exit(0);
    }
printf("len0=%d\n",ftell(fp));				/*输出当前位置*/
    ch = fgetc(fp);
    while (ch != EOF)
    {
        putchar(ch);								/*输出字符*/
        ch = fgetc(fp); 							/*获取fp指向文件中的字符*/
    }
    printf("\n");
printf("len1=%d\n",ftell(fp));   			/*输出位置指针的当前位置*/ 
rewind(fp);						/*指针指向文件开头*/
printf("len2=%d\n",ftell(fp));				/*输出位置指针当前位置*/
    ch = fgetc(fp);	
    while (ch != EOF)
    {
        putchar(ch); 							/*输出字符*/
        ch = fgetc(fp);
    }
    printf("\n");
    fclose(fp); 									/*关闭文件*/
}

C标准库的I/O缓冲区

C标准库调用fopen()函数都会给文件分配一个I/O缓冲区,来加速读写操作。

为文件分配内存缓冲区的大小,直接影响到实际操作外村设备的数量,配的越大,操作外存的数量越少,读写速度越快,效率提高。

缓冲区分为三种

全缓冲区:

缓冲区写满了,就写回内核。普通文件通常是全缓冲的。

行缓冲区:

数据中带有"\n"就把张写回内核。标准输入和标准输出对应终端设备时通常是行缓存的。

无缓冲:

标准错误输出通常是无缓冲的。

设置缓冲区属性

#include<stdio.h>
void setbuf(FILE *stream,char *buf);
void setbuffer(FILE *stream,char *buf,size_t size);
void setlinebuf(FILE *stream);
int setvbuf(FILE *stream,char *buf,int mode,size_t size);

setbuf()函数设置buf所指的缓冲区大小。缓冲区大小有两个,一个是BUFSIZ(全缓冲区),一个是NULL(无缓冲)。
setbuffer()和setbuf()函数相同,但可以指定缓冲区大小。
setlinebuf()函数设置为行缓冲。
setvbuf()函数融合了上面3种函数的功能。mode的取值_IOFBF(全缓冲)、_IOLBT(行缓冲)、_IONBF(无缓冲)

调用成功返回0;失败返回非0值。

清空缓冲区

flush()将I/O缓冲区数据强制保存到磁盘文件中。

fflush()函数

#include<stdio.h>
int fflush(FILE *stream);

将缓冲区中尚未写入文件的数据强制性写入文件,然后清空缓冲区。

如果stream为NULL,则会将所有打开的文件数据更新。 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值