C语言_10 文件操作

10 文件操作

10.1 概述
10.1.1 磁盘文件和设备文件

  • 磁盘文件
    指一组相关数据的有序集合,通常存储在外部介质(如磁盘)上。使用式才调入内存。
  • 设备文件
    在操作系统中把每一个与主机相连的输入、输出设备看作是一个文件,把它们的输入、输出等同于对磁盘文件的读和写。

10.1.2 磁盘文件的类型
计算机的存储在物理上二进制的,所以物理上所有的磁盘文件本质上都是一样的:以字节为单位进行顺序存储。
C语言_10 文件操作_第1张图片
从用户或者操作系统使用的角度(逻辑上)把文件分为:

  • 文本文件:基于字符编码的文件
  • 二进制文件:基于值编码的文件

10.1.3 文本文件和二进制文件
(1)文本文件

  • 基于字符编码,常见编码有ASCII、UNCODE等
  • 一般可以使用文本编辑器直接打开
  • 数5678以ASCII存储形式(ASCII码)为: ‘5’(ASCII 53) 00110101
    00110101 00110110 00110111 00111000
    (2)二进制文件
  • 基于值编码,自己根据具体应用,指定某个值是什么意思
  • 把内存中的数据按其在内存中的存储形式原样输出到磁盘上
  • 数5678的存储形式(二进制码)为:00010110 00101110

10.2 文件的打开和关闭
10.2.1 文件指针
在C语言中用一个指针变量指向一个文件,这个指针称为文件指针。

#include
typedef struct
{
     
	short level;//缓冲区“满”或者“空”的程序
	unsigned flags;//文件状态标志
	char fd;//文件描述符
	unsigned char hold;//如无缓冲区不读取字符
	short bsize;//缓冲区大小
	unsigned char *buffer;//数据缓冲区的位置
	unsigned ar;//指针,当前的指向
	unsigned istemp;//临时文件,指示器
	short token;//用于有效性的检查
}FILE;
int main01()
{
     
	//FILE
	return 0;
}

FILE是系统使用typedef定义出来的有关文件信息的一种结构体类型,结构中有文件名、文件状态和文件当前位置等信息
声明FILE结构体类型的信息包含在头文件"stdio.h"中,一般设置一个指向FILE类型变量的指针变量,然后通过它来引用这些FILE类型变量。通过文件指针就可以对它所指的文件进行各种操作。
C语言_10 文件操作_第2张图片
C语言中有三个特殊的文件指针由系统默认打开,用户无需定义即可直接使用

  • stdin:标准输入,默认当前终端(键盘),我们使用的scanf、getchar函数默认从此终端获得数据。
  • stdout:标准输出,默认为当前终端(屏幕),我们使用的printf、puts函数默认输出信息到此终端。
  • stderr:标准出错,默认为当前终端(屏幕),我们使用的perror函数默认输出信息到此终端。。

C语言_10 文件操作_第3张图片
10.2.2 文件的打开
任何文件使用之前必须打开:

#include
FILE *fopen(const char *filename,const char *mode);

功能:打开文件
参数:filename:需要打开的文件名,根据需要加上路径
mode:打开文件的模式设置
返回值:成功:文件指针 失败:NULL
第一个参数的几种形式:

#include
int main02()
{
     
	//先在D:\下创建一个文件a.txt
	//FILE *fp=fopen("D:/a.txt","r");//路径斜杠 /或反斜杠\\
	FILE *fp_passwd=NULL;
	//相对路径 
	//打开当前目录passwd文件:源文件(源程序所在目录)
	FILE *fp_passwd=fopen("passwd.txt","r");
	//打开当前目录(text)下passwd.txt文件
	fp_passwd=fopen("./test/passwd.txt","r");
	//打开当前目录上一级目录(相对当前目录)passwd.txt文件
	fp_passwd=fopen("../passwd.txt","r");
	//绝对路径
	fp_passwd=fopen("c:/test/passwd.txt","r");
	
	/*
	文件打开失败原因:
	1.找不到文件 
	2.文件权限(读 写 执行)
	3.程序打开文件超出上限 65535 ungsined short类型最大值
	先判断文件打开是否成功,若失败操作的是空指针
	*/
	if(fp==NULL)
	{
     
		printf("文件打开失败\n");
		return -1;	
	}
	printf("文件打开成功:%p\n",fp);
	fclose(fp);//改变此文件指针,无法关闭
	return 0;
}

第二个参数的几种形式(打开文件的方式):
C语言_10 文件操作_第4张图片
注意:

  • b是二进制模式的意思,b只是在Windows有效,在Linux用r和rb的结果是一样的
  • Unix和Linux下所有的文本文件行都是\n结尾,而Windows所有的文本文件行都是\r\n结尾
  • 在Windowa平下,以“文本”方式打开文件,不加b:
    当读取文件的时候,系统会将所有的"\r\n"转换成"\n"
    当写入文件的时候,系统会将"\n"转换成"\r\n"写入
    以“二进制”方式打开文件,则读写\n都不会进行这样的转换
  • 在Unix/Linux平台下,“文本”与“二进制”模式没有区别,"\r\n"作为两个字符原样输入输出

10.2.3 文件的关闭
任何文件在使用后应该关闭:

  • 打开的文件会占用内存资源,如果总是打开不关闭,会消耗很多内存
  • 一个进程同时打开的文件数是有限制的,超过最大同时打开文件数,再次调用fopen打开文件会失败
  • 如果没有明确的调用fclose关闭打开的文件,那么程序在退出的时候,操作系统会同一关闭
#include
FILE fclose(FILE *stream);

功能:关闭先前fopen()打开的文件。此动作让缓冲区的数据写入文件中,并释放系统所提供的文件资源。
参数:stream:文件指针
返回值:成功:0 失败:-1

10.3 文件的顺序读法
10.3.1 按照字符读写文件fgetc、fputc
(1)写文件

#include
int fputc(int ch,FILE *stream);

功能:将ch转换为unsigned后写入stream指定的文件中
参数:ch:需要写入文件的字符 stream:文件指针
返回值:成功:成功写入文件的字符 失败:-1
(2)文件结尾
在C语言中,EOF表示文件结束符(end of file)。在while循环中EOF作为文件结束标志,这种以EOF作为文件结束标志的文件,必须是文本文件。在文本文件中,数据都是以字符的ASCII代码值的形式存放。我们知道,ASCII代码值得范围时0~127,不可能出现-1,因此可以用EOP作为文件结束标志。

#define EOF (-1)

当把数据以二进制形式存放到文件中时,就会有-1值得出现,因此不采用EOF作为二进制文件的结束标志。为解决这一问题,ANSI C提供一个feof函数,用来判断文件是否结束。feof函数可以判断二进制文件有可用以判断文本文件

#include
int feof(FILE *stream);

功能:检测是否读取到了文件结尾。判断的是最后一次“读操作的内容”,不是当前位置内容(上一个内容)。
参数:stream:文件指针
返回值:非0值:已经到文件结尾 0:没有到文件结尾
(3)读文件

#include
int fgetc(FILE *stream);

功能:从stream指定的文件中读取一个字符
参数:stream:文件指针
返回值:成功:返回读取到的字符 失败:-1

#include
int main03()
{
     
	FILE *fp=fopen("D:/a.txt","r");
	if(!fp)
	{
     
		printf("文件打开失败\n");
		return -1;	
	}
	char ch;
	//文件的字符读取 文件默认结尾为-1
	ch=fgetc(fp);
	printf("%c\n",ch);
	//fp++ 不能修改文件指针 文件在读取时光标流自动向下移动
	//关闭文件
	fclose(fp);
	return 0; 
}
int main04()
{
     
	FILE *fp=fopen("D:/a.txt","r");
	if(!fp)
	{
     
		printf("文件打开失败\n");
		return -1;	
	}
	char ch;
	while(ch=fgetc(fp))!=EOF{
     
		printf("%c\n",ch);
	}
	fclose(fp);
	return 0; 
}
int main05()
{
     
	//以写的方式打开文件,如果文件不存在会创建一个新文件 如果文件存在 会清空内容
	FILE *fp=fopen("D:/a.txt","w");
	if(!fp)
	{
     
		printf("文件打开失败\n");
		return -1;	
	}
	char ch='a';
	//字符写入
	fputc(ch,fp);
	fclose(fp);
	return 0; 
}
int main06()
{
     
	FILE *fp=fopen("D:/a.c","w");
	if(!fp)
	{
     
		printf("文件打开失败\n");
		return -1;	
	}
	char ch;
	while(1)
	{
     
		scanf(%c,&ch);
		if(ch=='@')
		{
     
			break;
		}
		fputc(ch,fp);
	}
	fclose(fp);
	return 0; 
}

简单的加密解密:

#include
//加密
int main07()
{
     
	FILE *fp1=fopen("D:/解密.txt","r");
	FILE *fp2=fopen("D:/加密.txt","w");
	if(!fp1||!fp2)
	{
     
		printf("文件打开失败\n");
		return -1;
	}
	char ch;
	while((ch=fgetc(fp1))!=EOF)
	{
     
		ch++;
		fputc(ch,fp2);
	}
	fclose(fp1);
	fclose(fp2);
	renturn 0;
}
```c
#include
//解密
int main08()
{
     
	FILE *fp1=fopen("D:/加密.txt","r");
	FILE *fp2=fopen("D:/解密文件.txt","w");
	if(!fp1||!fp2)
	{
     
		printf("文件打开失败\n");
		return -1;
	}
	char ch;
	while((ch=fgetc(fp1))!=EOF)
	{
     
		ch--;//加随机数无法解密
		fputc(ch,fp2);
	}
	fclose(fp1);
	fclose(fp2);
	renturn 0;
}

10.3.2 按照行读写文件fgets、fputs
(1)写文件

#include
int fputs(const char *str,FILE *stream);

功能:将str所指定的字符串写入stream指定的文件中,字符串结束符’\0’不写入文件。
参数:str:字符串 stream:文件指针
返回值:成功:0 失败:-1
(2)读文件

#include
int fgets(char *str,int size,FILE *stream);

功能:从stream指定的文件内读取字符,保存到str所指定的内存空间,直到出现换行符、读到文件结尾或是已读了size-1个字符为止,最后会自动加上字符’\0’作为字符串结束。
参数:str:字符串 size:指定最大读取字符串的长度(size-1) stream:文件指针
返回值:成功:成功读取的字符串 读到文件尾或出错:NULL

#include
int main09()
{
     
	FILE *fp=fopen("D:/a.txt","r");
	if(!fp)
	{
     
		printf("文件打开失败\n");
		return -1;	
	}
	char *p=(char *)malloc(sizeof(char)*100);
	memset(p,0,sizeof(char)*100);
	fgets(p,100,fp);
	printf("%s\n",p);
	free(p);
	fclose(fp);
	return 0;
}
int main10()
{
     
	FILE *fp=fopen("D:/a.txt","r");
	if(!fp)
	{
     
		printf("文件打开失败\n");
		return -1;	
	}
	char *p=(char *)malloc(sizeof(char)*100);
	while(!feof(fp))//feof 返回0 没有到文件结尾
	{
     
		memset(p,0,sizeof(char)*100);
		fgets(p,100,fp);
		printf("%s\n",p);
	}
	free(p);
	fclose(fp);
	return 0;
}
int main11()
{
     
	FILE *fp=fopen("D:/b.txt","r");
	if(!fp)
	{
     
		printf("文件打开失败\n");
		return -1;	
	}
	char ch[]="我喜欢学英语";//遇到\0停止
	fputs(ch,fp);
	fclose(fp);
	return 0;
}
#include
#include
int main12()
{
     
	FILE *fp=fopen("D:/b.txt","w");
	if(!fp)
	{
     
		printf("文件打开失败\n");
		return -1;	
	}
	char *p=(char *)malloc(sizeof(char)*1024);
	while(1)
	{
     
		memset(p,0,sizeof(char)*1024);
		//scanf("%s",p);//无法显示换行符
		//fgets()接收用户输入字符
		scanf("%[^\n]",p);//接收非换行符
		getchar();//吞噬回车\n
		//停止输入命令 comm=exit
		if(!strcmp(p,"comm=exit"))
			break;
		//字符串追加\n
		strcat(p,"\n");
		fputs(p,fp);
	}
	free(p);
	fclose(fp);
	return 0;
}

四则运算:10+2=
值 运算符 值=\n sprintf
sprintf 直接打印到字符串中
printf 直接在命令行上输出

#include
#include
#include
enum opt
{
     
	add,sub,mlt,dive
};//op;
int main13() 
{
     
	srand((size_t)time(NULL));
	FILE *fp=fopen("D:/四则运算.txt","w");
	if(!fp)
	{
     
		printf("文件打开失败\n");
		return -1;	
	}
	int a,b;
	char c;//+ - * /
	char *p=(char*)malloc(sizeof(char)*20);
	for(int i=0;i<100;i++)
	{
     
		a=rand()*10+1;
		b=rand()*10+1;
		switch(rand()%4)//(op)
		{
     
			case add:
				c='+';
				break;
			case sub:
				c='-';
				break;	
			case mlt:
				c='*';
				break;
			case dive:
				c='/';
				break;
			//default:
				//break;
		}
		memset(p,0,20);
		sprintf(p,"%d%c%d\n",a,c,b);
		fputs(p,fp);//fgets(p,size,fp)
	}
	free(p);
	fclose(fp);
	//p=NULL;
	//fp=NULL;
	return 0;
}
```c
#include
enum opt
{
     
	add,sub,mlt,dive
};//op;
int main14() 
{
     
	FILE *fp1=fopen("D:/四则运算.txt","r");
	FILE *fp2=fopen("D:/四则运算结果.txt","w");
	if(!fp1||!fp2)
	{
     
		printf("文件打开失败\n");
		return -1;	
	}
	//!feof(fp); EOF -1
	int a,b;
	char c;
	char *p=(char*)malloc(sizeof(char)*20);
	for(int i=0;i<100;i++)
	{
     
		memset(p,0,20);
		fgets(p,20,fp1);
		//6*6=\n
		sscanf(p,"%d%c%d=\n",&a,&c,&b);
		switch(c)
		{
     
			case '+':sum=a+b;break;
			case '-':sum=a-b;break;
			case '*':sum=a*b;break;
			case '/':sum=a/b;break;
		}
		memset(p,0,20);	
		sprintf(p,"%d%c%d=%d\n",a,c,b,sum);	
		fputs(p,fp2);
	}
	free(p);
	fclose(fp1);
	fclose(fp2);
	return 0;
}

(3)强化训练:文件版四则运算
有个文件大小不确定,每行内容都是一个四则运算表达式,还没有算出结果,写一个程序,自动算出其结果后修改文件。
C语言_10 文件操作_第5张图片

在这里插入代码片

10.3.3 按照格式化文件fprintf、fscanf
(1)写文件

#include
int fprintf(FILE *stream,const char *format,...);

功能:根据参数format字符串来转换并格式化数据,然后将结果输出到stream指定的文件中,指定出现字符串结束符’\0’位置。
参数:stream:已经打开的文件 format:字符串格式,用法和printf()一样
返回值:成功:实际写入文件的字符个数 失败:-1
(2)读文件

#include
int fscanf(FILE *stream,const char *format,...);

功能:从stream指定的文件中读取字符串,并根据参数format字符串来转换并格式化数据。
参数:stream:已经打开的文件 format:字符串格式,用法和scanf()一样
返回值:成功:参数数目,成功转换的值的个数 失败:-1

#include
int main15() 
{
     
	FILE *fp=fopen("D:/a.txt","r");
	if(!fp)
	{
     
		printf("文件打开失败\n");
		return -1;	
	}
	char *p=(char*)malloc(sizeof(char)*100);
	int a;
	fscanf(fp,"%3d",&a);
	printf("%d\n",a);
	
	fscanf(fp,"%s",p);	
	printf("%s",p);	

	free(p);
	fclose(fp);
	return 0;
}
#include
int main16() 
{
     
	FILE *fp=fopen("D:/b.txt","r");
	if(!fp)
	{
     
		printf("文件打开失败\n");
		return -1;	
	}
	int a,b,c;
	fscanf(fp,"%d+%%d",&a,&b,&c);
	printf("%d\n",a);
	printf("%d\n",b);
	printf("%d\n",c);
	
	fclose(fp);
	return 0;
}
int main17() //把hello world写进去
{
     
	FILE *fp=fopen("D:/b.txt","w");
	if(!fp)
	{
     
		printf("文件打开失败\n");
		return -1;	
	}
	//char ch[]="hello world";
	//fprintf(fp,"%s",ch);
	
	int a=10;
	fprintf(fp,"%05d",a);//00010
	fprintf(fp,"%05x",a);//0000a
	
	fclose(fp);
	return 0;
}
int main17() //把hello world读出来
{
     
	FILE *fp=fopen("D:/b.txt","r");
	if(!fp)
	{
     
		printf("文件打开失败\n");
		return -1;	
	}
	char ch[20];
	//fscanf(fp,"%s",ch);//hello 遇到空格结束
	fscanf(fp,"%[^\n]",ch);//hello world
	printf("%s\n",ch);
	
	//char ch[20]={0};//初始化
	memset(ch,0,20);
	fscanf(fp,"%11c",ch);//hello world 不带\0
	//fscanf(fp,"%3s",ch);//hel 没有初始化也带\0
	printf("%s\n",ch);
	
	int a;
	fscanf(fp,"%x",&a);
	printf("%d\n",a);//10
	
	free(p);
	fclose(fp);
	return 0;
}

四则运算:

#include
#include
#include
int main18() 
{
     
	srand((size_t)time(NULL));
	FILE *fp=fopen("D:/四则运算.txt","w");
	if(!fp)
	{
     
		printf("文件打开失败\n");
		return -1;	
	}
	int a,b;
	char c;
	for(int i=0;i<100;i++)
	{
     
		a=rand()%10+1;
		b=rand()%10+1;
		switch(rand()%4)//
		{
     
			case 0:c='+';break;
			case 1:c='-';break;
			case 2:c='*';break;
			case 3:c='/';break;	
		}
		fprintf(fp,"%d%c%d=\n",a,c,b);
	}
	fclose(fp);
	return 0;
}
int main19() 
{
     
	srand((size_t)time(NULL));
	FILE *fp1=fopen("D:/四则运算.txt","r");
	FILE *fp2=fopen("D:/四则运算结果.txt","w");
	if(!fp1||!fp1)
	{
     
		printf("文件打开失败\n");
		return -1;	
	}
	int a,b,sum;
	char c;
	for(int i=0;i<100;i++)
	{
     
		fscanf(fp1,"%d%c%d=\n",&a,&c,&b);
		switch(c)//
		{
     
			case '+':sum=a+b;break;
			case '-':sum=a-b;break;
			case '*':sum=a*b;break;
			case '/':sum=a/b;break;	
		}
		fprintf(fp2,"%d%c%d=%d\n",a,c,b,sum);
	}
	fclose(fp1);
	fclose(fp2);
	return 0;
}

大文件排序:

#include
#include
#include
#define SIZE 1000
int main20() //生成文件
{
     
	srand((size_t)time(NULL));
	FILE *fp=fopen("D:/数据.txt","w");
	if(!fp)
	{
     
		printf("文件打开失败\n");
		return -1;	
	}
	for(int i=0;i<1000;i++)
	{
     
		fprintf(fp,"%d\n",rand()%256);//rand()%256 0-255	
	}
	fclose(fp);
	return 0;
}
void BubbleSort(int *src,int len);//函数声明
int main21() //排序
{
     
	FILE *fp1=fopen("D:/数据.txt","r");
	FILE *fp2=fopen("D:/数据冒泡版排序.txt","w");
	if(!fp1||!fp2)
	{
     
		printf("文件打开失败\n");
		return -1;	
	}
	//冒泡版
	int *arr=(int *)malloc(sizeof(int)*1000);
	for(int i=0;i<1000;i++)
	{
     
		fscanf(fp1,"%d\n",&arr[i]);
	}
	BubbleSort(arr,SIZE);
	for(int i=0;i<1000;i++)
	{
     
		fprintf(fp2,"%d\n",&arr[i]);
	}
	free(arr);
	fclose(fp1);
	fclose(fp2);
	return 0;
}
int main22() //排序
{
     
	FILE *fp1=fopen("D:/数据.txt","r");
	FILE *fp2=fopen("D:/数据插直接入版排序.txt","w");
	if(!fp1||!fp2)
	{
     
		printf("文件打开失败\n");
		return -1;	
	}
	//直接插入版 数比较多,且在一个范围内的
	int *arr=(int *)malloc(sizeof(int)*256);
	memset(arr,0,sizeof(int)*256);
	for(int i=0;i<1000;i++)
	{
     
		int value;
		fscanf(fp1,"%d\n",&value);
		arr[value]++;//将数据的个数放在对应的下标里面
	}
	for(int i=0;i<256;i++)
	{
     
		for(int j=0;j<arr[i];j++)
		{
     
			fprintf(fp2,"%d\n",i);
		}
	}
	free(arr);
	fclose(fp1);
	fclose(fp2);
	return 0;
}

10.3.4 按照块读写文件fread、fwrite
(1)写文件

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

功能:以数据块的方式给文件写入内容 把 buf 中的“sizenmemb”个字节写到文件 fp 中
参数:ptr:准备写入文件数据的地址
size:size_t为unsigned int类型,此参数指定写入文件内容的块数据大小
nmemb:写入文件的块数,写入文件数据总大小为:size
nmemb
stream:已经打开的文件指针
返回值:成功:实际成功写入文件数据的块数目,此值和nmemb相等
失败:0

#include
#include
#include
int main23() //写入
{
     
	FILE *fp=fopen("D:/c.txt","wb");
	if(!fp)
	{
     
		printf("文件打开失败\n");
		return -1;	
	}
	//int a=4567;
	//fwrite(&a,sizeof(int),1,fp);
	
	int arr[]={
     1,2,3,4,5,6,7,8,9,10};
	fwrite(&a,sizeof(int),10,fp);
	fclose(fp);
	return 0;
}
int main23() //读取
{
     
	FILE *fp=fopen("D:/c.txt","rb");
	if(!fp)
	{
     
		printf("文件打开失败\n");
		return -1;	
	}
	//int value;
	//fwrite(&value,sizeof(int),1,fp);
	//printf("%d\n",value);
	
	int arr[0]={
     0};
	fwrite(&value,sizeof(int),10,fp);
	//fwrite(&value,2,20,fp);
	//fwrite(&value,10,4,fp);//只要块的总大小一直即可,一般写第一种
	for(int i=0;i<10;i++)
	{
     
		printf("%d\n",arr[i]);
	}
	fclose(fp);
	return 0;
}

(2)读文件

#include
int fread(const void *ptr,size_t size,size_t nmemb,FILE *stream);

功能:以数据块的方式给文件读取内容 从文件 fp 中读出“sizenmemb”个字节保存到 buf 中
参数:ptr:存放读取出来数据的存放空间
size:size_t为unsigned int类型,此参数指定读取文件内容的块数据大小
nmemb:读取文件的块数,读取文件数据总大小为:size
nmemb
stream:已经打开的文件指针
返回值:成功:实际成功读取到文件数据的块数目,如果此值比nmemb小,但大于0,说明读到文件的结尾
失败:0

文件读写结构体:

#include
#include
#include
struct student student
{
     
	char name[21];
	int age;
	int score;
	char addr[51];
}stu;
int main24() //写入
{
     
	stu ss[3]=
	{
     
		{
     "张三",9,10,"河北"},
		{
     "李四",91,100,"河北"},
		{
     "王五",29,30,"河北"}
	};
	FILE *fp=fopen("D:/d.txt","wb");
	if(!fp)
	{
     
		printf("文件打开失败\n");
		return -1;	
	}
	for(int i=0;i>3;i++)
	{
     
		fwrite(&ss[i],sizeof(stu),1,fp);//ss数组大小 stu结构体大小
	}
	fclose(fp);
	return 0;
}
int main25() //读取
{
     
	FILE *fp=fopen("D:/c.txt","rb");
	stu *ss=(stu *)malloc(sizeof(stu)*3);
	if(!fp)
	{
     
		printf("文件打开失败\n");
		return -1;	
	}
	int i=0;
	while(!feof(fp))
	{
     
		fread(&ss[i],sizeof(stu),1,fp);		
		i++;
	}
	for(int i=0;i<3;i++)
	{
     
		printf("姓名:%s\n",ss[i].name);
		printf("年龄:%d\n",ss[i].age);
		printf("成绩:%d\n",ss[i].score);
		printf("家乡:%s\n",ss[i].addr);
	}
	free(p);
	fclose(fp);
	return 0;
}

大文件拷贝:

#include
#include
#include
#define SIZE 1024
//若SIZE大小为1024*1024*8 在拷贝文件前先判断文件大小,若>8M 先开辟8M空间;若<8M 有多大开辟多大空间 通过属性判断大小-->10.6 
//获取文件状态 stat main28()
int main26(int argc,char *argv)//传递参数个数,传递参数内容
{
     
	
	//for(int i=0;i
	//{
     
	//	printf("姓名:%s\n",argv[i]);	
	//}
	//用户输入参数缺少
	if(argc<3)
	{
     
		printf("缺少参数\n");
		return -1;
	}
	// 拷贝命令D:/copy.exe 需要打开的内容D:/test.avi 拷贝到这个文件D:/Code/test.avi
	//argv[0] 程序名称 文件大小50M
	FILE *fp1=fopen(argv[1],"rb");//argv[1] 第一个真正参数
	FILE *fp2=fopen(argv[2],"wb");
	if(!fp1||!fp2)
	{
     
		printf("复制文件出错\n");
		return -2;	
	}
	char *temp=(char *)malloc(sizeof(char)*1024);
	//count 读取成功实际个数
	int count=0;
	while(!feof(fp1))
	{
     
		memset(temp,0,1024);
		count=fread(temp,sizeof(char),1024,fp1);
		fwrite(temp,sizeof(char),count,fp2);
	}
	free(temp);
	fclose(fp1);
	fclose(fp2);
	return 0;
}

fread这句话出问题,假设在读的时候最后没有读满1024字节,读了100字节,SIZE仍然按1024算,出错。fread返回 读取成功的有效个数count,作为fwrite写入的操作
C语言_10 文件操作_第6张图片
C语言_10 文件操作_第7张图片

#include
#include
#include

#include
#include
#define SIZE (1024*1024*8)
int main28(int argc,char *argv)
{
     
	//用户输入参数缺少
	if(argc<3)
	{
     
		printf("缺少参数\n");
		return -1;
	}
	// 拷贝命令D:/copy.exe 需要打开的内容D:/test.avi 拷贝到这个文件D:/Code/test.avi
	//argv[0] 程序名称 文件大小50M
	FILE *fp1=fopen(argv[1],"rb");//argv[1] 第一个真正参数
	FILE *fp2=fopen(argv[2],"wb");
	if(!fp1||!fp2)
	{
     
		printf("复制文件出错\n");
		return -2;	
	}
	char *temp=NULL;
	int size=0;//文件size实际大小
	struct stat st;
	stat(argv[1],&st);
	//根据文件实际大小开辟空间
	if(st.st_size>SIZE)
	{
     
		temp=(char *)malloc(sizeof(char)*SIZE);
		size=SIZE;
	}
	else
	{
     
		temp=(char *)malloc(sizeof(char)*st.st_size+10);//加额外空间保证够用
		size=st.st_time+10;
	}
	int count=0;//count 读取成功实际个数
	while(!feof(fp1))
	{
     
		memset(temp,0,size);
		count=fread(temp,sizeof(char),size,fp1);
		fwrite(temp,sizeof(char),count,fp2);
	}
	free(temp);
	fclose(fp1);
	fclose(fp2);
	return 0;
}

10.4 文件随机读写

#include
int fseek(FILE *stream,long offset,int whenece);

功能:移动文件流(文件光标)的读写位置
参数:stream:已经打开的文件指针
offset:根据whence来移动的位移数(偏移量),可以是正数,也可以式负数。如果是正数,则相对于whence往右移动,如果是负数,则相对于whence往左移动。如果向前移动的字节数超过了文件开头则出错返回,如果向后移动的字节数超过了文件末尾,再次写入时将增大文件尺寸。
whence:其取值如下:
SEEK_SET:从文件开头移动offset个字节 #define SEEK_SET 0
SEEK_CUR:从当前位置移动offset个字节 #define SEEK_CUR 1
SEEK_END:从文件末尾移动offset个字节 #define SEEK_END 2
返回值:成功:0 失败:-1

#include
#include
#include
int main29()
{
     
	FILE *fp=fopen("D:/a.txt","r");
	if(!fp)
	{
     
		printf("文件打开失败\n");
		return -1;	
	}
	char arr[100];
	memset(temp,0,100);
	fgets(arr,100,fp);
	printf("%s",arr);
	//文件随机读写
	//fseek(fp,-8,SEEK_CUR);//fseek(fp,-8,1);
	//memset(temp,0,100);
	//fgets(arr,100,fp);
	//printf("%s",arr);
	
	//从文件起始位置开始偏移
	fseek(fp,11,SEEK_SET);//fseek(fp,11,0);
	memset(temp,0,100);
	fgets(arr,100,fp);
	printf("%s",arr);
	
	fseek(fp,-17,SEEK_END);//fseek(fp,-17,2);
	memset(temp,0,100);
	fgets(arr,100,fp);
	printf("%s",arr);
	
	fclose(fp);	
	return 0;
}
#include
void rewind(FILE *stream);

功能:把文件流(文件光标)的读写位置移动到文件开头
参数:stream:已经打开的文件指针
返回值:无返回值

#include
#include
#include
int main30()
{
     
	FILE *fp=fopen("D:/a.txt","r+");//r+可读可写方式打开文件
	//此处不写a 会先把文件内容预读到文件缓冲区中,再新建一个缓冲区(值为0),以追加a的方式会把这两个缓冲区拼接在一起,不会改变原来的内容
	if(!fp)
	{
     
		printf("文件打开失败\n");
		return -1;	
	}
	long pos=ftell(fp);
	printf("%ld\n",pos);
	
	fseek(fp,-17,SEEK_END);//fseek(fp,-17,2);
	//fputs("我爱学英语;\n",fp);
	long pos=ftell(fp);
	printf("%ld\n",pos);
	
	fclose(fp);	
	return 0;
}
int main31()
{
     
	FILE *fp=fopen("D:/b.txt","w");
	if(!fp)
	{
     
		printf("文件打开失败\n");
		return -1;	
	}
	char ch1[]="hello 哈哈哈\n";
	char ch2[]="world";
	fputs(ch1,fp);
	fseek(fp,-14,SEEK_CUR);//txt默认每行最后\r\n
	fputs(ch2,fp);
	
	fclose(fp);	
	return 0;
}

会把之前的覆盖掉
C语言_10 文件操作_第8张图片

#include
long ftell(FILE *stream);

功能:获取文件流(文件光标)的读写位置
参数:stream:已经打开的文件指针
返回值:成功:当前文件流(文件光标)的读写位置 失败:-1

#include
#include
#include
int main32()
{
     
	FILE *fp=fopen("D:/a.txt","r");
	if(!fp)
	{
     
		printf("文件打开失败\n");
		return -1;	
	}
	char arr[100];
	long pos=ftell(fp);//获取文件光标流所在位置
	printf("%ld\n",pos);
	fgets(arr,100,fp);
	long pos=ftell(fp);
	printf("%ld\n",pos);

	rewind(fp);//重置文件光标在起始位置 fseek(fp,0,SEEK_SET);
	memset(arr,0,100);//为防止之前字符串污染 清空
	fgets(arr,100,fp);
	printf("%s\n",arr);
	
	fclose(fp);	
	return 0;
}

10.5 Windows和Linux文本文件区别

  • b是二进制模式的意思,b只是在Windows有效,在Linux用r和rb的结果是一样的
  • Unix和Linux下所有的文本文件行都是\n结尾,而Windows所有的文本文件行都是\r\n结尾
  • 在Windows平台下,以“文本”形式打开文件,不加b:
    当读取文件的时候,系统会将所有的"\r\n"转换成"\n"
    当写入文件的时候,系统会将"\n"转换成"\r\n"
    以“二进制”方式打开文件,则读\写都不会进行这样的转换
  • 在Unix/Linux平台下,“文本”与“二进制”模式没有区别,"\r\n"作为两个字符原样输入输出
    判断文本文件是Linux格式还是Windows格式:
#include
int main(int argc, char **args)
{
     
	if (argc < 2)
		return 0;
	FILE *p = fopen(args[1], "rb");
	if (!p)
		return 0;
	char a[1024] = {
      0 };
	fgets(a, sizeof(a), p);
	int len = 0;
	while (a[len])
	{
     
		if (a[len] == '\n')
        {
     
        	if (a[len - 1] == '\r')
            {
     
            	printf("windows file\n");
            }
            else
            {
     
            	printf("linux file\n");
            }
        }
        len++;
	}
	fclose(p); 
	return 0;
} 

10.6 获取文件状态

#include
#include
int stat(const char *path,struct stat *buf);

功能:获取文件状态信息(相当于 右键点击文件 属性)
参数:path:文件路径 buf:保存文件信息的结构体 结构体指针类型
返回值:成功:0 失败:-1
文件信息:
C语言_10 文件操作_第9张图片

#include
#include
#include

#include
#include
/*
获取文件状态
1.导入头文件
2.定义结构体变量 通过函数获取内容
3.找到结构体变量 进行打印操作
*/
int main27()
{
     
	//文件状态结构体变量
	struct stat st;
	stat("D:/copy.exe",&st);//对结构体变量取地址就是结构体指针
	printf("文件大小:%d\n",st.st_size);
	return 0;
}

10.7 删除文件、重命名文件名

#include
int remove(const char *pathname);

功能:删除文件
参数:pathname:文件名
返回值:成功:0 失败:-1

#include
int rename(const char *oldpath,const char *newpath);

功能:把oldpath的文件名改为newpath
参数:oldpath:旧文件名 newpath:新文件名
返回值:成功:0 失败:-1

#include
#include
#include
int main33()
{
     
	int value=remove("D:/b.txt");//直接删除 不会到回收站里去
	if (value==0)
	{
     
		printf("删除成功\n");
	}
	else
	{
     
		printf("删除失败\n");
	}
	return 0;
}
int main34()
{
     
	//重命名
	int value=rename("D:/a.txt","D:/abc.txt");
	//移动文件 剪切
	int value=rename("D:/abc.txt","D:/Code/abc.txt");
	if (value==0)
	{
     
		printf("重命名成功\n");
	}
	else
	{
     
		printf("重命名失败\n");
	}
	return 0;
}

10.8 文件缓冲区
10.8.1 文件缓冲区
缓冲区:硬盘和内存之间的区域,内存与硬盘频繁交互 伤硬盘 读取速度慢
ANSI C标准采用“缓冲文件系统”处理数据文件。
所谓缓冲文件系统是指系统自动地在内存区为程序中每一个正在使用的文件开辟一个文件缓冲区,从内存向磁盘输出数据必须先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘去。
如果从磁盘向计算机读入数据,则一次从磁盘文件将一批数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(给程序变量)。

10.8.2 磁盘文件的存取
C语言_10 文件操作_第10张图片

  • 磁盘数据,一般保存在硬盘、U盘等掉电不丢失的磁盘设备中,在需要时调入内存
  • 在内存中对文件进行编辑处理后,保存到磁盘中
  • 程序与磁盘之间交互,不是立即完成的,系统或程序可根据需要设置缓冲区,以提高存取效率

10.8.3 更新缓冲区
更新条件:1.时间到达一定程度保存 2.字数写的够多的保存

#include
int fflush(FILE *stream);

功能:更新缓冲区,让缓冲区的数据立马写到文件中
参数:stream:文件指针
返回值:成功:0 失败:-1

#include
#include
#include
int main35()
{
     
	FILE *fp=fopen("D:/a.txt","w+");
	if(!fp)
	{
     
		printf("文件打开失败\n");
		return -1;	
	}
	while(1)
	{
     
		scanf("%c",&ch);
		if(ch=='@')
			break;
		//if() 平时在经过判断之后再更新缓冲区
		fflush(fp);//频繁和硬盘交互 损伤硬盘
		fputc(ch,fp);
	}
	fclose(fp);	
	return 0;
}

快易通核心代码
C语言_10 文件操作_第11张图片
单词库
对单词表进行读取操作,在程序中建立结构体,一个结构体有两个参数(单词 翻译),结构体成员为指针(2个指针)
第一个单词:#a
第二个单词:#a.m.
Trans:也不需要,需要n.上午 读完单词
第三个单词:#a/c

dict.c:

#include
#include
#include
#include"dict.h"
#define SIZE 3
/*
1.创建结构体存储单词和翻译
2.读取单词 格式化存储对应的堆空间中
3.单词查找
4.销毁堆空间
*/
//函数声明
int GetWord()
{
     
	FILE *fp=fopen("D:/d.txt","r");//打开文件
	if(!fp)
	{
     
		printf("加载单词库失败\n");
		return -1;
	}
	list=(dict *)malloc(sizeof(dict)*3);//创建控件
		//创建索引
	index=(pos *)malloc(sizeof(pos)*27);//0-26表示字母 27表示下标
	char flag='a';//记录当前索引标志位,查看是哪个字母,如果是a 起始位置不变 结束位置+1
	index[0].start=0;//记录a的索引
	index[0].end=0;
	int idx =0;//26的字母是哪个 字母对应的索引
	
	int i=0;//数组下标
	//结构体中两个都是指针char类型 开辟空间存储值
	char * temp=(char *)malloc(sizeof(char)*1024);
	while(!feof(fp))//读取单词 判断是否为结尾
	{
     
		memset(temp,0,1024);
		fgets(temp,1024,fp);
		
		//开辟单词堆空间 #a\n\0
		//去掉\n
		temp[strlen(temp)-1]=0;
		//+1存\0
		//list[i].word=(char *)malloc(sizeof(char)*strlen(temp)+1);
		list[i].word=(char *)malloc(sizeof(char)*strlen(temp));
		//将单词放在指定堆空间中
		strcpy(list[i].word,&temp[1]);//去掉# 拷贝时从下标为1开始
		
		//创建索引 0-25	a:index[0].start index[0].end	b
		if(idx!=26)//下标为26进入中文
		{
     
			if(list[i].word[0]==flag)
			{
     
				index[idx].end++;//单词首字母为a,结束位置++
			}
			else
			{
     
				idx++;
				index[idx].start=index[idx-1].end+1;
				index[idx].end=index[idx-1].end+1;
				flag++;
				//index[idx].end=index[idx].start=index[idx-1].end+1;
				//int a=b=10;
			}
		}
		memset(temp,0,1024);
		fgets(temp,1024,fp);//Trans:art. 一;字母A\n 开辟20 +\0最后开辟14个
		//去掉\n
		temp[strlen(temp)-1]=0;
		list[i].trans=(char *)malloc(sizeof(char)*strlen(trans)-5);
		strcpy(list[i].trans,&temp[6]);

		i++;
	}
	//释放和关闭文件操作
	free(temp);
	fclose(fp);
	
	//记录中文索引
	index[26].start=index[25].end;
	index[26].end=SIZE;
	//记录英文索引
	for(int i=0;i<27;i++)
	{
     
		printf("%c的起始位置:%d\n",'a'+i,index[i].start);
		printf("%c的起始位置:%d\n",'a'+i,index[i].end);
	}
	
	//for(int i=0;i
	//{
     
	//	printf("%s\n",list[i].word);
	//	printf("%s",list[i].trans);
	//}
	//如果返回值类型为int
	return i;
}
int SearchWord(char *word,char *trans);
{
     
	if(!word||!trans)//传递空或空指针操作失败报错
	{
     
		printf("输入异常\n");//exit(-1);
		return -1;
	}
	for(int i=0;i<SIZE;i++)
	{
     
		//如果用户输入的单词和词库中相同返回单词对应的翻译
		if(!strcmp(word,list[i].word))//两单词相同 返回值0
		{
     
			strcpy(trans,list[i].trans);
			return 0;
		}
	}
	return 1;
}
void DestorySpace()
{
     
	if(!list)//(list==NULL)
		reutrn;
	if(index)
	{
     
		free(index);
		index=NULL;
	}
	for(int i=0;i<SIZE;i++)//次数应该
	{
     
		free(list[i].word);
		free(list[i].trans);
	}
	free(list);
	list(NULL);
}
int main36()
{
     
	//获取单词和翻译
	GetWord();
	//接收用户输入的单词
	char *word=(char *)malloc(sizeof(char)*1024);
	//根据单词提供翻译
	char *trans=(char *)malloc(sizeof(char)*1024);
	while(1)
	{
     
		memset(word,0,1024);
		memset(trans,0,1024);
		scanf("%s",word);
		//gets(word);
		//scanf("%^[\n]",word);//接收带空格的
		//出口
		if(!strcmp(word,"comm=exit"))
		{
     
			break;
		}
		if(!SearchWord(word,trans))
		{
     
			printf("%s\n",trans);
		}
		else
		{
     
			printf("未找到该单词");
		}
	}
	//数据销毁
	DestorySpace();
	return 0;
}

多文件编程:
头文件dict.h://做解释,全局变量的定义 结构体创建 函数的声明

#pragma once
#include
//结构体声明
typedef struct DICT
{
     
	char * word;
	char * trans;
}dict;

//定义索引 0-25	index[0].start index[0].end 起始位置 结束位置
typedef struct POSITION
{
     
	int start;
	int end;
}pos;

//打开文件后创建堆空间存储数据,建立结构体全局变量
//dict *list=(dict *)malloc(sizeof(dict)*3);//报错 malloc是函数只能在函数中写

//存储单词和翻译的数组
dict * list=NULL;//若NULL报错需导入#include
//记录单词的下标 索引指针
pos *index=NULL;

//函数声明
//extern int GetWord();//一般不写extern
int GetWord();
int SearchWord(char *word,char *trans);//ctrl+.自动创建函数
void DestorySpace();

C语言_10 文件操作_第12张图片
对于分多行的单词库:
首先写测试单词有多少行的程序(2行为一个单词):

#include
#include
#include
int main()
{
     
	FILE *fp=fopen("D:/dict.txt","r");
	if(!fp)
		return -1;
	char *temp=(char *)malloc(sizeof(char)*1024);
	int i=0;//没读一行都有行位计数器
	while(!feof(fp))
	{
     
		fgets(temp,1024,fp);
		i++;
	}
	printf("%d\n",i);
	fclose(fp);
	return 0;
}

当用户查找单词时,SearchWord可以改为 再添加一个查找首字母
int SearchWord(char *word,char *trans,int idx);
int SearchWord(char *word,char *trans,char ch);

dict.c:

#include
#include
#include
#include"dict.h"
#define SIZE 3
int GetWord()
{
     
	FILE *fp=fopen("D:/d.txt","r");//打开文件
	if(!fp)
	{
     
		printf("加载单词库失败\n");
		return -1;
	}
	list=(dict *)malloc(sizeof(dict)*3);//创建控件
		//创建索引
	index=(pos *)malloc(sizeof(pos)*27);//0-26表示字母 27表示下标
	char flag='a';//记录当前索引标志位,查看是哪个字母,如果是a 起始位置不变 结束位置+1
	index[0].start=0;//记录a的索引
	index[0].end=0;
	int idx =0;//26的字母是哪个 字母对应的索引
	
	int i=0;//数组下标
	//结构体中两个都是指针char类型 开辟空间存储值
	char * temp=(char *)malloc(sizeof(char)*1024);
	while(!feof(fp))//读取单词 判断是否为结尾
	{
     
		memset(temp,0,1024);
		fgets(temp,1024,fp);
		
		//开辟单词堆空间 #a\n\0
		//去掉\n
		temp[strlen(temp)-1]=0;
		//+1存\0
		//list[i].word=(char *)malloc(sizeof(char)*strlen(temp)+1);
		list[i].word=(char *)malloc(sizeof(char)*strlen(temp));
		//将单词放在指定堆空间中
		strcpy(list[i].word,&temp[1]);//去掉# 拷贝时从下标为1开始
		
		//创建索引 0-25	a:index[0].start index[0].end	b
		if(idx!=26)//下标为26进入中文
		{
     
			if(list[i].word[0]==flag)
			{
     
				index[idx].end++;//单词首字母为a,结束位置++
			}
			else
			{
     
				idx++;
				index[idx].start=index[idx-1].end+1;
				index[idx].end=index[idx-1].end+1;
				flag++;
				//index[idx].end=index[idx].start=index[idx-1].end+1;
				//int a=b=10;
			}
		}
		memset(temp,0,1024);
		fgets(temp,1024,fp);//Trans:art. 一;字母A\n 开辟20 +\0最后开辟14个
		//去掉\n
		temp[strlen(temp)-1]=0;
		list[i].trans=(char *)malloc(sizeof(char)*strlen(trans)-5);
		strcpy(list[i].trans,&temp[6]);

		i++;
	}
	//释放和关闭文件操作
	free(temp);
	fclose(fp);
	
	//记录中文索引
	index[26].start=index[25].end;
	index[26].end=SIZE;
	//记录英文索引
	for(int i=0;i<27;i++)
	{
     
		printf("%c的起始位置:%d\n",'a'+i,index[i].start);
		printf("%c的起始位置:%d\n",'a'+i,index[i].end);
	}
	
	//for(int i=0;i
	//{
     
	//	printf("%s\n",list[i].word);
	//	printf("%s",list[i].trans);
	//}
	//如果返回值类型为int
	return i;
}
int SearchWord(char *word,char *trans,int idx);
{
     
	if(!word||!trans)//传递空或空指针操作失败报错
	{
     
		printf("输入异常\n");//exit(-1);
		return -1;
	}
	for(int i=index[idx].start;i<index[idx].end;i++)
	{
     
		//如果用户输入的单词和词库中相同返回单词对应的翻译
		if(!strcmp(word,list[i].word))//两单词相同 返回值0
		{
     
			strcpy(trans,list[i].trans);
			return 0;
		}
	}
	return 1;
}
void DestorySpace()
{
     
	if(!list)//(list==NULL)
		reutrn;
	if(index)
	{
     
		free(index);
		index=NULL;
	}
	for(int i=0;i<SIZE;i++)//次数应该
	{
     
		free(list[i].word);
		free(list[i].trans);
	}
	free(list);
	list(NULL);
}
int main36()
{
     
	//获取单词和翻译
	GetWord();
	//接收用户输入的单词
	char *word=(char *)malloc(sizeof(char)*1024);
	//根据单词提供翻译
	char *trans=(char *)malloc(sizeof(char)*1024);
	int idx=0;
	while(1)
	{
     
		memset(word,0,1024);
		memset(trans,0,1024);
		scanf("%s",word);
		//gets(word);
		//scanf("%^[\n]",word);//接收带空格的
		//出口
		if(!strcmp(word,"comm=exit"))
		{
     
			break;
		}
		if(*word>='a'&&*word<='z')//word[0]首字母
		{
     
			idx=*word-'a';
		}
		else
		{
     
			idx=26;//中文
		}
		//0-26
		if(!SearchWord(word,trans,idx))
		{
     
			printf("%s\n",trans);
		}
		else
		{
     
			printf("未找到该单词");
		}
	}
	//数据销毁
	DestorySpace();
	return 0;
}

多文件编程:
头文件dict.h://做解释,全局变量的定义 结构体创建 函数的声明

#pragma once
#include
//结构体声明
typedef struct DICT
{
     
	char * word;
	char * trans;
}dict;

//定义索引 0-25	index[0].start index[0].end 起始位置 结束位置
typedef struct POSITION
{
     
	int start;
	int end;
}pos;

//打开文件后创建堆空间存储数据,建立结构体全局变量
//dict *list=(dict *)malloc(sizeof(dict)*3);//报错 malloc是函数只能在函数中写

//存储单词和翻译的数组
dict * list=NULL;//若NULL报错需导入#include
//记录单词的下标 索引指针
pos *index=NULL;

//函数声明
//extern int GetWord();//一般不写extern
int GetWord();
int SearchWord(char *word,char *trans,int idx);//ctrl+.自动创建函数
void DestorySpace();

你可能感兴趣的:(C语言)