C语言文件输入输出

一、文件
1、文件

文件通常是磁盘或固态硬盘上面的一段已命名的储存区。所有文件的内容都是以二进制形式(0或1)储存。

2、文本模式和二进制模式

文本文件:文件最初使用二进制编码(ASCII或者Unicode)的字符表示文本,改文件就是文本文件,其中包含文本内容。
二进制文件:如果文件中的二进制代表机器语言或者数值数据(使用相同的内部表示,假设,用long或者double类型的值)或图片或音乐编码,改文件就是二进制文件,其中包含二进制文件。
C语言提供俩种访问文件的途径:二进制模式和文本模式。二进制模式中,程序可以访问文件的每个字节。在文本模式中门程序所见的内容和文件的实际内容不同。

3、标准文件

C语言会自动打开三个文件,他们被称为标准输入、标准输出和标准错误输出。在默认情况下,标准输入是系统的普通输入设备,如键盘;标准输出和标准错误输出系统的普通输出设备,如显示器。

二、标准I/O
1、fopen函数

extern FILE *fopen( const char *__filename, const char *__type );
fopen的第一个参数是待打开文件的名称,第二个参数指定打开文件的模式。

模式字符串含义
“r”以只读模式打开文件
“w”以写模式打开,把现有文件的长度截为0,如果文件不存在,则创建一个新文件
“a”以写模式打开,在现有文件末尾添加内容,如果文件不存在,则创建一个新文件
“r+”以更新模式打开文件(即可以读写文件)
“w+”以更新模式打开文件(即,读和写),把现有文件的长度截为0,如果文件不存在,则创建一个新文件
“a+”以更新模式打开文件(即,读和写),在现有文件末尾添加内容,如果文件不存在,则创建一个新文件;可以读整个文件,但是只能从末尾添加内容
“rb”、“wb” 、“ab” 、
“rb+”、“r+b”、“wb+”、
“w+b”、“ab+”、
“a+b”
与上一个模式相同,但是以二进制打开文件
2、getc()和putc()函数
ch=getc(fp);

上面的语句表示从fp指定的文件中获取一个字符。

putc(ch, fpout);

上面的语句是把字符ch放入到FILE指针fpot指定的文件中。

3、文件结尾

如果getc()函数在读取一个字符发现是文件结尾,它将返回一个特殊值EOF。所以C程序只有在读到超过文件末尾时才会发现文件的结尾。

4、fclose()函数

fclose(fp)函数关闭指定的文件,必要时刷新缓冲区。如果成功关闭,fclose()函数返回0,否则返回EOF。

5、示例
/*
*  压缩文件为原来的三分之一  
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LEN 40

int main(int argc, char *argv[]) 
{
    FILE *in, *out;
    int ch;
    char name[LEN];
    int count = 0;

    // 检查命令行参数
    if( argc < 2)
    {
        fprintf(stderr, "Usage:  %s filename\n", argv[0]);
        exit(1);
    }
    //fprintf(stderr, "11111111111112. \n ");
    // 实现输入
    if( (in = fopen( argv[1] , "r" ) ) == NULL )
    {
        fprintf(stderr, "I couldn't open the file \"%s\" \n ", argv[1]);
        exit(2);
    }
    // 实现输出
    if ( (out = fopen(name, "w") ) == NULL )        // 打开文件以供写入
    {
        fprintf(stderr, "Can't create output file . \n ");
        exit(3);
    }
    while( (ch = getc(in)) != EOF )
    {
        if (count++ % 3 == 0)
        {
            putc(ch, out);      // 打印每3个字符中的1个
        }
    }
    if( fclose(in) != 0 || fclose(out) != 0 )
    {
        fprintf(stderr, "Error in closing file . \n ");
    }

    return 0;
}
三、文件I/O:fprintf()、fscanf()、fgets()和fputs
1、fprintf()、fscanf()
/* 使用fprintf()、fscanf()和rewind() */
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#define MAX 40

int main()
{

	FILE *fp;
	char words[MAX];
	if ((fp = fopen("wordy", "a+")) == NULL )
	{
		fprintf(stdout, "Can't open \"wordy\" file \n");
		exit(EXIT_FAILURE);
	}
	
	puts("请输入添加到文件中的单词,终止键#结束\n");
	puts("在一行的开头键入终止键\n");
	while((fscanf(stdin, "%40s", words) == 1) && (words[0] != '#'))
	{
		fprintf(fp, "%s\n", words);	
	}
	puts("文件内容:");
	rewind(fp);	// 返回文件开始处
	while(fscanf(fp, "%s", words) == 1)
	{
		puts(words);
	}
	puts("完成!");
	if(fclose(fp) != 0)
	{
		fprintf(stderr, "ERR CLOSE FILE \n");
	}

	return 0;
}
2、fgets()和fputs()
fgets(buf, STLEN, fp);

buf是char类型数组的名称,STLEN是字符串的大小,fp是指向FILE的指针。
fgets()函数读取到第一个换行符的后面,或者读到文件结尾,或者读取到STLEN-1个字符。然后fgets在末尾添加一个空字符使之成为一个空字符串。如果 fgets()在读到字符上限之前已读完一整行,它会把表示行结尾的换行符放在空字符前面。fgets()函数在遇到EOF时将返回NULL值,可以利用这一机制检查是否到达文件结尾。

fputs(buf, fp);

fputs()接受俩个参数,第一个是字符串的地址;第二个是文件指针。该函数根据传入地址找到的字符串写入指定文件。和puts()函数不同,fputs在打印字符串时不会在其末尾添加换行符。

四、随机访问:fseek()和ftell()
#include <stdio.h>
#include <stdlib.h>
#define SLEN 81


int main()
{
	char file[SLEN];
	char ch;
	FILE *fp;
	long count = 0; 
	long last = 0;
	
	puts("请输入你的文件名:");
	scanf("%80s", file);
	if( (fp = fopen(file, "rb")) == NULL )
	{
		printf("文件不能打开[%s]\n", file);
	}

	// 定位到文件末尾
	fseek(fp, 0L, SEEK_END);
	last = ftell(fp);
	for(count = 1L; count <= last; count++)
	{
		fseek(fp, -count, SEEK_END);
		ch = getc(fp);
		if(ch != EOF && ch != '\n')
		{
			putchar(ch);
		}
	}
	putchar('\n');
	fclose(fp);

	return 0;
}
1、fseek()和ftell()

fseek()的第一个参数是FILE指针,指向待查找的文件,fopen()应该已打开改文件;第二个参数是偏移量,该参数表示从起始点开始要偏移的距离,必须是long类型的值,可以为正(前移)、负(后移)、或0(保持不动);第三个参数是模式,该参数确定起始点。根据ANSI标准,在stdio.h规定了几个表示模式的明示变量。

模式偏移量的起始点
SEEK_SET文件开始处
SEEK_CUR当前位置
SEEK_END文件末尾

fseek()成功的返回值为0,失败返回-1。

ftell()函数的返回类型是long,它返回的是当前位置,ANSI标准把它定义在stdio.h中。

2、fgetpos()和fsetpos()函数
int fgetspos(FILE * restrict stream, fpost_t * restrict ps);

把fpos_t类型的值放在pos指向的位置上,成功返回0,失败返回非0。
int fsetpos(FILE *stream, const fpos_t *pos);
使用pst指向位置上的fpos_t类型值来设置文件指针指向该指定的位置。成功返回0,失败返回非0。

五、其他标准I/O函数
1、int ungetsc(int c, FILE *fp)

int ungetsc(int c, FILE *fp)把c指定的字符放回到输入流中。

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

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

3、int setvbuf()函数
int setvbuf(FILE * restrict fp, char * restrict buf, int mode, size_t size);

setvbuf()函数创建了一个供I/O函数替换使用的缓冲区。再打开文件后且未对文件流进行其他操作之前,调用该函数。指针fp识别待处理的流,buf指向待使用的储存区。如果buff的值不是NULL。则必须创建一个缓冲区。变量size告诉setvbuf()数组的大小。mode的选择如下:_IOFBF表示完全缓冲(在缓冲区满时刷新);_IOLBF表示行缓冲(在缓冲区满时写入一个换行符时);_INOBF表示无缓冲。如果成功,返回0,否则返回非0值。

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

操作二进制数据

5、size_t fwrite()函数
size_t fwrite(const void *restrict ptr, size_t size, size_t nmemb, FILE * restrict fp);

fwrite()函数把二进制数据文件写入文件。把数据写入文件。

char buffer[256];
fwrite(buffer, 256, 1, fp);

fwrite()函数返回成功写入项的数量,成功返回nmemb,如果写入错误,返回的值比nmemb小。

6、size_t fread()函数
size_t fread(const void *restrict ptr, size_t size, size_t nmemb, FILE * restrict fp);

ptr是待读取文件数据在内存中的地址,fp待读取的文件。

// 读取保存的内含10个double类型值的数组
double ear[10];
fread(ear, 10, 10, fp);

fread()函数返回成功读取的数量,成功返回nmemb,如果读取错误或读到文件结尾,返回的值比nmemb小。

7、int feof(FILE *fp)和int ferror(FILE *fp)函数

如果标准输入函数返回EOF,则通常表明函数已到达文件结尾。然而读取错误时,函数也会返回EOF, feof(FILE *fp)和ferror(FILE *fp)函数用于区分这俩种情况。当上一次输入调用检测文件结尾时,feof()函数返回一个非0值,否则返回0,。当读写出现错误,ferror()函数返回一个非0值,否则返回0。

8、把文件附加到另一个文件结尾
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BUFSIZE 4096
#define SLEN 81

void append(FILE *soure, FILE *dest);
char * s_gets(char * st, int n);


int main()
{

	FILE *fa;		// 目标文件
	FILE *fs;		// 源文件
	char file_app[SLEN];	// 目标文件名
	char file_src[SLEN];	// 源文件名
	int  files = 0;		// 附加的文件数量
	int  ch = 0;

	puts("请输入目标文件:");
	s_gets(file_app, SLEN);

	if((fa =fopen(file_app, "a+")) == NULL )
	{
		fprintf(stderr, "打开文件[%s]失败!!\n",file_app);
		exit(EXIT_FAILURE);
	}
	if(setvbuf(fa, NULL, _IOFBF, BUFSIZE) != 0)
	{
		fputs("创建缓冲区失败!!\n", stderr);
		exit(EXIT_FAILURE);
	}

	puts("请输入源文件:");
	while (s_gets(file_src, SLEN) && file_src[0] != '\0')
	{
		if(strcmp(file_src, file_app) == 0)
		{
			fputs("创建缓冲区失败!!\n", stderr);
		}
		else if((fs=fopen(file_src, "r")) == NULL)
		{
			fprintf(stderr, "打开文件[%s]失败!!\n", file_src);
		}
		else
		{
			if(setvbuf(fs, NULL, _IOFBF, BUFSIZE) != 0)
			{
				fputs("创建缓冲区失败!!\n", stderr);
				continue;
			}
			append(fs, fa);
			if(ferror(fs) != 0)
			{
				fprintf(stderr, "ERROR in 读取文件[%s]!!\n",file_src);
			}
			if(ferror(fa) != 0)
			{
				fprintf(stderr, "ERROR in 写入文件[%s]!!\n",file_app);
			}
			fclose(fs);
			files++;
			printf("文件[%s]追加完成", file_src);
			puts("下一个文件(空行退出)");
		}
	}

	printf("文件追加结束。[%d]文件追加\n", files);
	rewind(fa);	// 返回文件开始处
	printf("[%s]文件内容:\n", file_app);
	while ((ch = getc(fa)) != EOF)
	{
		putchar(ch);
	}
	puts("结束");
	fclose(fa);

	return 0;
}

void append(FILE *source, FILE *dest)
{
	size_t bytes;
	static char temp[BUFSIZE];   // 只分配一次

	while((bytes = fread(temp, sizeof(char), BUFSIZE, source)) > 0)
	{
		fwrite(temp, sizeof(char), bytes, dest);
	}
}

char * s_gets(char * st, int n)
{
	char *ret_val;
	char *find;

	ret_val = fgets(st, n, stdin);
	if(ret_val)
	{
		find = strchr(st, '\n');	// 查找替换符
		if(find)
		{
			*find = '\0';
		}
		else
		{
			while(getchar() != '\n')
			{
				continue;
			}

		}

	}
	return ret_val;
}
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值