文件I/O

文件输入/输出

相关函数

fopen()函数

该函数声明在<stdio.h>中,他的第一个参数是待打开文件的名称,更准确的说是一个包含该文件的字符串地址;第2个参数是一个字符串,指定待打开文件的模式

模式字符串含义
r以读模式打开文件
w以写模式打开文件,把现有文件的长度截为0[丢失该内容],如果文件不存在,则创建一个新文件
a以写模式打开文件,在现有文件内容末尾添加内容,如果文件不存在,则创建第一个新文件
r+以更新模式打开文件(即可以读写文件)
w+以更新模式打开文件,如果文件存在,则将文件的长度截为0;如果不存在,则创建一个新文件
a+以更新模式打开文件,在现有文件末尾添加内容,如果文件不存在则创建一个新文件;可以读取整个文件,但是只能从末尾添加内容
rb wb ab r+b w+b rb+ wb+…与上述类似,但是是以二进制打开

像UNIX和Linux这样只有一种文件类型的系统,带b字母和不带b字母的模式相同

新的C11新增了带x字母的写模式,与以前的写模式相比具有更多特性。第一:如果以传统的一种写模式打开一个现有文件,fopen()会把该文件的长度截为0,这样就丢失了该文件的内容。但是使用带x字母的写模式,即使fopen()操作失败,原文件的内容也不会被删除。第二:如果环境允许,x模式的独占特性使得其它程序或线程无法访问正在被打开的文件

程序成功打开文件后,fopen()将返回文件指针,其它I/O函数可以使用这个指针指定该文件。文件指针是指向FILE的指针,FILE是一个定义stdio.h中的派生类型。文件指针fp并不指向实际的文件,它指向一个包含文件信息的数据对象,其中包含操作文件的的I/O函数所用的缓冲区信息

getc()和putc()函数

getc()和putc()函数与getchar()和putchar()函数类似

FILE *fp;  // 文件指针
ch=getchar(); // 从标准输入中获取一个字符
ch=getc(fp);  // 从fp指定的文件中获取一个字符
putc(ch,fp); // 把字符ch放入FILE指针fp指定的文件中
fclose()函数

fclose(fp)函数关闭fp指定的文件,必要时刷新缓冲区;对于比较正式的程序,应该检查是否成功关闭文件,如果成功关闭,fclose()函数返回0,否则返回EOF

if(fclose(fp)!=0)
    printf("Erroe in closing file");
/* 如果磁盘已满、移动硬盘被移除或出现I/O错误,都会导致调用fclose()函数失败 */
fprintf()和fscanf()函数

文件I/O函数fprintf()和fscanf()函数的工作方式和printf()、scanf()类似;区别在于前者需要使用第1个参数指定待处理的文件[指向标准文件的指针]

FILE *fp;
int a;
fprintf(fp,"%s","aaa"); //输出aaa [成功写入返回写入字符个数,失败返回负数]
fscanf(fp,"%d",&n); //接受输入 [返回成功赋值个数]

fprintf(stdout,"aaa");  // 函数将会向显示器输出内容
fscanf(stdin,"%d",&a);  // 函数将会从键盘读取数据
rewind()函数
FILE *fp;
rewind(fp); // 返回到文件文件开始处
fgets()和fputs()函数

fgets()函数读取输入直到第1个换行符的后面;或读到文件结尾;或读到STLEN-1个字符。然后在fgets()末尾添加一个空字符使之成为一个字符串【保留读取到的换行符】。fgets()函数在遇到EOF时将返回NULL值,可以利用这一机制检查是否到达文件结尾;如果未遇到EOF则返回之前传给它的第一个参数地址

fgets(buf,STLEN,fp);
/*
buf:char类型数组的名称
STLEN:字符串的大小
fp:是指向FILE的指针
*/

fputs(buf,fp);
/*
buf:字符串的地址
fp:用于指定目标文件
*/

由于fgets()函数保留了换行符,fputs()就不会再添加

随机访问:fseek()和ftell()

有了fseek()函数,便可把文件看作是数组,在fopen()打开的文件直接移动到任意字节处

fseek(fp,offset,ms);
/*
fp:FILE指针,指向待查找的文件
offset:偏移量
ms:文件的起始点模式
*/
模式偏移量的起始点
SEEK_SET文件开始处
SEEK_CUR当前位置
SEEK_END文件末尾
// 示例【旧的实现可能缺少这些定义,可以使用数值0L、1L、2L分别表示这3种模式 L的后缀表明其值是long类型】
fseek(fp,0L,SEEK_SET); // 定位至文件开始处
fseek(fp,10L,SEEK_SET); // 定位至文件中的第10个字节处
fseek(fp,2L,SEEL_CUR); // 从文件当前位置前移2个字节
fseek(fp,0L,SEEK_END); // 定位至文件结尾处
fseek(fp,-10L,SEEK_END); // 从文件结尾处回退10个字节

如果一切正常,fseek()的返回值为0;如果出现错误(如试图移动的距离超出文件的范围),其返回值为-1

ftell()函数的返回类型是long,它返回的是参数指向文件的当前位置距文件开始处的字节数

fgetpos()和fsetpos()函数

fseek()和ftell()潜在问题是,它们都把文件大小限制在long类型能表示的范围内。ANSI C新增了两个处理较大文件的新定位函数:fgetpos()和fsetpos();这两个函数不使用long类型的值表示位置,它们使用一种新类型:fpos_t(文件定位类型)。fpos_t类型不是基本类型,它根据其他类型来定义,fpos_t类型的变量或数据对象可以在文件中指定一个位置,它不能是数组类型

// 成功返回0 失败返回非0
fgetpos(fp,pos); // fp:指向文件的指针  pos:文件的当前位置距文件开头的字节数【fpos_t类型】
fsetpos(fp,pos); // fp:指向文件的指针  pos:设置文件指针指向偏移该值后指定的位置【fpos_t类型】
ungetc()函数

int ungetc()函数把c指定的字符返回输入流中,如果把一个字符放回输入流,下次调用标准输入函数时将读取该字符。例如:假设要读取下一个冒号之前的所有字符,但是不包括冒号本身,可以使用getchar()和getc()函数读取字符到冒号,然后使用ungetc()函数把冒号放回输入流中。ANSI C标准保证每次只会放回一个字符,如果实现允许把一行中的多个字符放回输入流,那么下一次输函数读入的字符顺序与返回顺序相反

int ungetc(int c,FILE *fp);

在这里插入图片描述

fflush()函数
int fflush(FILE *fp);

调用fflush()函数引起输出缓冲区中所有的未写入数据被发送到fp指定的输出文件,这个过程称为刷新缓冲区。如果fp是空指针,所有输出缓冲区都被刷新。在输入流中使用fflush()函数的效果是未定义的,只要最近一次操作不是输入操作,就可以用该函数来更新流(任何读写模式)

setvbuf()函数

setvbuf()函数创建了一个供标准I/O函数替换使用的存储区;在打开文件后且未对流进行其他操作之前,调用该函数。

int setvbuf(fp,buf,type,size);
/*
fp:文件流指针
buf:缓冲区首地址【非NULL 则必须创建一个缓冲区】
type:缓冲区类型
size:缓冲区内字节的数量
*/

参数类型

  • _IOFBF(满缓冲):当缓冲区为空时,从流中读入数据;或当缓冲区满时,向流写入数据
  • _IOLBF(行缓冲):每次从流中读入一行数据或先流中写入一行数据
  • _IONBF(无缓冲):直接从流中读入数据或直接向流中写入数据,而没有缓冲区

【返回值】:成功返回0,失败返回非0

feof()和ferror()函数

如果标准输入函数返回EOF,则通常表明函数已到达文件结尾。然而,出现读取错误时,函数也会返回EOF。feof()和ferror()函数用于区分两种情况。

当上一次输入调用检测到文件结尾时,feof()函数返回一个非0值,否则返回0;

当读或写出现错误,ferror()函数返回一个非零值,否则返回0

指向标准文件的指针

<stdio.h>头文件爸3个文件指针和3个标准文件相关联,C程序会自动打开这3个标准文件

标准文件文件指针通常使用设备
标准输入stdin键盘
标准输出stdout显示器
标准错误stderr显示器

这些文件指针都是指向FILE的指针,所以它们可用作标准I/O函数的参数,如fclose(fp)中的fp

二进制模式和文本模式

UNIX只有一种文件格式,所以不需要进行特殊的转换。许多MS-DOS编辑器都是使用Ctrl+Z标记文本文件的结尾。以文本模式打开这样的文件时,C能识别作为文件结尾标记的字符。但是,以二进制模式打开相同的文件时,Ctrl+Z被看作是文件中的一个字符,而实际的文件结尾符在该字符后面。文件结尾符可能紧跟在Ctrl+Z字符后面,或在文件中可能用空字符填充

二进制I/O :fread()和fwrite()

为保证数值在存储前后一致,最精确的做法是使用与计算机相同的位组合来存储;因此,double类型的的值应该存储在一个double大小的单元中。如果以程序所用的表示法把数据存储在文件中,则称为以二进制形式存储数据。不存在从数值到字符串的转换过程,对于标准I/O,fread()和fwrite()函数用于以二进制形式处理数据

实际上,所有的数据都是以二进制形式存储的,甚至连字符都以字符码的二进制表示来存储。如果文件中的所有数据都被解释成字符码,则称该文件包含文本数据;如果部分或所有数据被解释成二进制形式的数值数据,则称该文件包含二进制数据(另外,用数据表示机器语言指令的文件都是二进制文件)

size_t fwrite()函数
//fwrite()函数把二进制数据写入文件,size_t是根据标准C类型定义的类型,它是sizeof运算符返回的类型 通常是unsigned int
size_t fwrite(ptr,size,nmemb,stream);
/*
ptr:写入数据地址
size、nmemb::总写入数字符数有size*nmemb决定
stream:文件指针
*/

// 示例:保存一个大小为256字节的数据对象(如数组)
char buffer[256];
fwrite(buffer,256,1,fp);

【返回值】:返回实际写入的nmemb数目 失败返回值会小于nmemb

size_t fread()函数
 size_t  fread(buffer, size, count, stream);
/*fread()函数:从文件流中读取数据
buffer:接受数据的地址
size:一个单元的大小
count:单元个数
stream:文件流
*/

// 示例:读取文件中10个double大小的值
double arr[10];
fread(arr,sizeof(double),10,fp);

fread()函数每次从stream中最多读取count个单元,每个单元大小为size个字节,将读取的数据放到buffer;文件流的位置指针后移size*count字节

【返回值】:返回实际读取的单元个数,小于count,则文件可能结束或读取出错

案例分析(二进制I/O读写)

通过命令行获取原始文件名和拷贝文件名,实现文件拷贝功能

#include <stdio.h>
#include <stdlib.h>
#define BUF 256 
void file_copy(FILE* fs,FILE* ft);

int main(int argc,char** argv)
{
	FILE* source; // 定义源文件指针 
	FILE* target; // 定义拷贝文件指针	
	
	if(argc!=3)
	{
		printf("Parameter error.");
		exit(EXIT_FAILURE); // 表示没有成功运行程序 返回1 
	}
	if((source=fopen(argv[1],"rb"))==NULL)  // 判断源文件是否读取成功
		printf("Can't open %s.\n",argv[1]);
	if((target=fopen(argv[2],"wb"))==NULL)
		printf("Can't open %s.\n",argv[2]); // 判断拷贝文件是否读取成功
	file_copy(source,target);
	
	printf("Success copy.");
	return 0;
}

void file_copy(FILE* fs,FILE* ft)  // 文件拷贝函数
{
	size_t bt; // 存储 fread()返回值 
	static char str[BUF]; // 定义存储数组
	
	while((bt=fread(str,sizeof(char),BUF,fs))>0)
		fwrite(str,sizeof(char),bt,ft);
	
}

编译程序
编译程序
在这里插入图片描述
运行编译文件
在这里插入图片描述
查看结果
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Meaauf

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值