小言_互联网的博客

C语言学习笔记之文件操作

279人阅读  评论(0)

12.1C语言中的文件

在操作系统中,为了统一对各种硬件的操作,简化接口,不同的硬件设备被看成文件,因此对文件操作就等同于对磁盘上普通文件的操作。
对文件的操作:打开、读、写、执行、关闭。
文件流

12.2C语言打开文件

stdin、stdout、stderr是由系统打开的,可直接使用。

<stdio.h>头文件的fopen()函数:
FILE *fopen(char *filename,char *mode)

fopen()函数的返回值:fopen函数会获取文件信息(文件名、文件状态、当前读写位置),并将这些信息保存到一个FILE类型的结构体变量中,然后将该变量的地址返回。
FILE *fp=fopen(“D:\demo.txt”,“rb+”);

注:在打开文件时一定要判断文件是否打开成功。
等于运算符的优先级高于赋值运算符。

FILE *fp;
if (fp=fopen("D:\\demo.txt","rb+")==NULL)
{
   
	printf("fail to open\n");
	exit(0);
}

fopen函数的打开方式:
文件的读、写、更新
文件分为文本文件和二进制文,默认是文本文件。

关闭文件:

int fclose(FILE *fp) {
   
	fclose(fp);
}

文件打开和关闭的实例:

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

#define N 100
int main() {
   
	File *fp;

	if ((fp=fopen("D:\\demo.txt","rb+"))==NULL)
	{
   
		printf("fail to open\n");	
	}
	exit(0);

	fclose(fp);
	return 0;
}

12.3文本文件和二进制文件的区别

文本本质上也是二进制

12.4以字符形式读写文件

12.5以字符串形式读写文件

12.6以数据块的形式读写文件

fgetc
fputc
(fgetc和fputc函数每次只能读写一个字符,速度较慢。)
fgets
fputs
(fgets和fputs函数每次只能读写一行)
fread
fwrite
(fread和fwrite函数一次可以读取多行数据)

注:对于windows使用fread和fwrite函数应以二进制的形式打开文件。

fread函数:
fread函数用来从指定文件中读取块数据。所谓块数据就是若干个字节的数据。

注:typedef定义的数据类型后面需要加_t

size_t fread(void *ptr,size_t size,size_t count,FILE *fp)
size_t是在stdio.h和stdlib.h头文件中使用typedef定义的数据类型表示无符号整数(内存区块的指针、每个数据块的字节数、数据的数量、文件指针)

#include<stdio.h>
#include<stdlib.h>
#pragma warning(disable:4996)

#define N 100

int main() {
   
	int a[N], b[N];
	FILE *fp;
	int size = sizeof(int);

	if ((fp=fopen("D:\\del","rb+"))==NULL)
	{
   
		printf("fail to open");
		exit(0);
	}
	for (int i = 0; i < N; i++)
	{
   
		scanf_s("%d",&a[i]);
	}
	

	fwrite(a,size,N,fp);

	rewind(fp);
	fread(b , size, N, fp);

	for (int i = 0; i < N; i++)
	{
   
		printf("%d\n",b[i]);
	}

	fclose(fp);
	return 0;
}

如何调试程序?怎样加深记忆、提高效率?

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

#pragma warning(disable:4996)

#define N 2

struct stu
{
   
	char name[10];
	int num;
	int age;
	float score;
}ba[N],bb[N], *pa, *pb;

int main() {
   
	FILE *fp;
	pa=ba;
	pb=bb;
	if ((fp=fopen("d:\\del.txt","wb+"))==NULL)
	{
   
		printf("fail to open\n");
		exit(0);
	}
	for (int i = 0; i < N; i++,pa++)
	{
   
		scanf_s("%s %d %d %f", pa->name, &pa->num, &pa->age, &pa->score);
	}
	
	fwrite(ba,sizeof(struct stu),N,fp);
	rewind(fp);
	fread(bb, sizeof(struct stu), N, fp);

	for (int i = 0; i < N; i++,pb++)
	{
   
		printf("%s %d %d %f",pb->name,pb->num,pb->age,pb->score);
	}
	fclose(fp);
	return 0;
}

12.7格式化读写文件

辨析:
fscanf和fprint函数都是格式化读写函数,他们的读写对象是磁盘文件。
scanf和printf是格式化读写函数,他们的写对象是键盘,读对象是显示器。

12.8随机读写文件

随机读写:读写可以从文件的任意位置,需要先移动文件内部的指针,再进行读写。

文件的定位:实现随机读写的关键是要按照要求移动位置指针。

rewind函数:将位置指针移动到文件开头,其原型为
void rewind(FILE *fp)
fseek函数用来将位置指针移动到任意位置,其原型为
int fseek (FILE *fp,long offset,int origin)
SEEK_SET
SEEK_CUR
SEEK_END
注:fseek函数一般用于二进制文件,在文本文件中由于要进行转换,计算的位置有时会出错。

文件的随机读写:先移动位置指针,再进行函数读写。

下面代码执行不对???

#include<stdio.h>
#include<stdlib.h>
#pragma warning (disable:4996)
#define N 3
struct stu
{
   
	char name[10];
	int num;
	int age;
	float score;
}boy[N],boys,*pb;

int main() {
   
	FILE *fp;
	int m = sizeof(struct stu);
	pb=boy;

	if ((fp = fopen("d:\\de.txt", "wb+")) == NULL)
	{
   
		printf("FAIL TO OPEN\n");
		exit(1);
	}

	printf("input data\n");
	for (int i = 0; i < N; i++,pb++)
	{
   
		scanf("%s %d %d %f",pb->name,&pb->num,&pb->age,&pb->score);
	}

	fwrite(boy,m,N,fp);
	fseek(fp,m,SEEK_SET);
	fread(boy,m,1,fp);
	printf("%s %d %d %f",boys.name,boys.num,boys.age,boys.score);
	fclose(fp);
	return 0;

12.9 C语言实现文件复制功能
文件复制的思路:首先开辟一个缓冲区,再将原文件的数据读到缓冲区,每读完一次就将缓冲区中的内容写入到新建的文件,直到原文件读完。

需要解决的两个关键问题:
(1)开辟多大的缓冲区?避免跨扇区读取.
(2)缓冲区中的数据没有结束标志,如果缓冲区填充不满,如何确定写入的字节数?

回忆一下fread函数的原型
size_t fread(void *ptr,size_t size,size_t count,FILE *fp)
注:fopen一定要以二进制的形式打开文件,不能以文本形式打开。

12.10FILE结构体以及缓冲区探讨

文件指针:指针变量指向的是文件
注:fopen函数的打开方式
读文件的时候文件必须存在
wb+的作用很大

控制缓冲区:缓冲区和输入流
缓冲区的基地址是不变的,利用指针指向下一个要被读取字符的地址,缓冲区没有数据的时候要将指针刷新,将指针重新指向基地址,。
注:换行符也当成一个字节处理。
缓冲区的刷新就是将指针ptr变为缓冲区的基地址,同时cnt的值为0,因为刷新之后缓冲区没有数据???
可以这样理解么,如果输入流还有数据,那么缓冲区的刷新就是指针指向的刷新,cnt取决于实际情况,如果输入流没有数据了,缓冲区的刷新就是指针指向的刷新,cnt此时的实际情况就是0

12.11C语言获取文件的长度

自己编写函数即可

12.12插入、删除、更改文件内容

顺序文件
散列文件
索引文件

如何插入数据:杯子思想
如何删除数据:临时文件

在实际开发过程中,我们往往会保持新旧数据长度一致,进而减少编程的工作量。
注:实际编程中应该多学、多问、多思考,效率优先,不能死磕不会的,遇到困难需要及时寻求团队的能力并调度资源,进而高效、高质量的完成任务。
文件复制函数、文件删除函数、文件插入函数类比学习???
文件复制函数:
fread函数的定义:
size_t fread(void *ptr,size_t size,size_t count,FILE *fp)
文件复制函数:

/*
文件复制函数(这就是编程中的需求开发,有人想要实现文件复制,开发人员根据需求写出来这个功能)
fSource 要复制的原文件
offsetSource相对原文件的位置偏移
len要复制的内容长度,如果len小于0则需要复制offsetSource后边的所有内容
fTarget要复制到的目标文件
offsetTarget相对目标文件的位置偏移
return成功复制的字节数
*/

long fcopy(FILE *fSource, long offsetSource, long len, FILE *fTarget, long offsetTarget) {
   
	int bufferLen = 1024 * 4;
	char *buffer = (char *)malloc(bufferLen);
	int readCount;
	long nBytes = 0;
	int n = 0;
	
	fseek(fSource,offsetSource,SEEK_SET);
	fseek(fTarget,offsetTarget,SEEK_SET);

	if (len<0)
	{
   
		while ((readCount=fread(buffer,1,bufferLen,fSource))>0)
		{
   
			nBytes += readCount;
			fwrite(buffer,readCount,1,fTarget);
		}
		

	}
	else
	{
   
		n = (int)ceil((double)((double)len / bufferLen));//需要完整进入缓冲区的次数
		for (int i = 1; i <= n; i++)
		{
   
			if (len-nBytes<bufferLen)//一次不完整的占据缓冲区
			{
   
				bufferLen = len - nBytes;//
			}
			readCount=fread(buffer,1,bufferLen,fSource);//fread读取的字节数为n次完整的缓冲区和一次可能的不完整缓冲区
			fwrite(buffer,readCount,1,fTarget);	
			nBytes += readCount;
		}
	}
	fflush(fTarget);
	free(buffer);
	return nBytes;
}

注:p判断语句要全面考虑
文件内容插入函数:

/*
fp 文件参数,要插入内容的文件
offset 相对文件开头的偏移量
buffer 将插入内容放到的缓冲区大小
len 要插入的内容长度

fileTemp 文件复制时创建的临时文件
len 返回超过插入的字节数

*/
#include<stdio.h>
#include<stdlib.h>
long finsert(FILE *fp, int offset, void *buffer, int len) {
   
	long fileSize = fsize(fp)
		File *fileTemp;
	if (offset>fileSize||offset<0||len<0)
	{
   
		return -1;
	}
	if (offset==fileSize)
	{
   
		fseek(fp,offset,SEEK_SET);
		if (!fwrite(buffer,len,1,fp))
		{
   
			return -1;
		}
	}
	if (offset<fileSize)
	{
   
		fpTemp=tmpfile();//tmpfile()创建临时文件之后会被删除
		fcopy(fp, 0, offset, fpTemp, 0);//将前offset个字符保存下来,写入临时文件
		fwrite(buffer, len, 1, fpTemp);//在临时文件写len个字节
		fcopy(fp,offset,-1,fpTemp,offset+len);//将原文件offset之后的字节放到临时文件offset+len个字节长度内
		freopen(FILENAME,"wb+",fp);//freopne函数
		fcopy(fpTemp,0,-1,fp,0);
		fclose(fpTemp);
	}
	return 0;
}

注:tmpfile函数用来创建一个临时的二进制文件,可以读取和写入数据,相当于fopen函数以wb+方式打开文件,该临时文件不会和当前存在的文件重名,并且会在调用fclose后或者程序结束后自动删除。

文件内容删除函数:

#include<stdio.h>
long fdelete(FILE *fp, long offset, int len) {
   
	
	long fileSize = getFileSize(fp);
	FILE *fpTemp;
		if (offset>fileSize||offset<0||len<0)
	    {
   
			return -1;
	    }
		fpTemp = tmpfile();
		fcopy(fp,0,offset,fpTemp,0);
		fcopy(fp, offset + len, -1, fpTemp, offset)
			freopen(FILENAME,"wb+",fp);
		fcopy(fpTemp,0,-1,fp,0);
		fclose(fpTemp);
		return 0;

	}

转载:https://blog.csdn.net/BJTUYBYUAN/article/details/117231673
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场