栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C语言文件操作

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C语言文件操作

文章目录
  • 文件指针和文件信息区
  • 二进制文件和文本文件
    • 如何用vs查看二进制文件
  • 文件缓冲区
  • 文件的打开和关闭
  • 文件的顺序读写
    • fgetc
    • fputc
    • fgets
    • fputs
    • fscanf
    • fprintf
    • fwrite
    • fread
    • sscanf和sprintf
  • 文件的随机读写
    • fseek
    • ftell
    • rewind
  • 文件结束判定
    • ferror和feof

文件指针和文件信息区

每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是有系统声明的,取名FILE.

FILE结构体大致是这样,每个编译器都不太相同,但大同小异

struct _iobuf {
        char *_ptr;
        int   _cnt;
        char *_base;
        int   _flag;
        int   _file;
        int   _charbuf;
        int   _bufsiz;
        char *_tmpfname;
       };
typedef struct _iobuf FILE;

上面说的都不重要。我们只需要知道有这么一个文件信息区就可以了。

我们使用的时候不需要关注这些细节。我们只需要知道我们可以用文件指针来指向这块文件信息区就可以了。

FILE* pf//文件指针

二进制文件和文本文件

二进制文件就是指文件里面的数据都是二进制。
文本文件就是指文件里面的数据都是由ASCII翻译而来。

举个例子:
在文件里面存放数字10000.
二进制文件存储的就是10000的十六进制,占用的内存是4个字节(一个整型)
文本文件就是把1变成字符1,0变成字符0,存放进文件里面。占用的内存是5个字节。(5个字符)

如何用vs查看二进制文件

先写一个二进制文件。

int main()
{
	FILE* pf = fopen("C:\Users\86135\Desktop\test.txt", "wb");
	if (pf == NULL)
	{
		perror("fopen:");
		return -1;
	}
	int i = 10000;
	fwrite(&i, sizeof(int), 1, pf);
	fclose(pf);
	pf = NULL;
	return 0;
}

我们是看不懂的。

添加现有项,然后用二进制编辑器查看。

我们就可以看到这个信息。这是10000的十六进制形式。

文件缓冲区

从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。

下面用一段代码来说明:

int main()
{
	FILE* pf = fopen("test.txt", "w");
	fputs("abcdef", pf);//先将代码放在输出缓冲区
	printf("睡眠10秒-已经写数据了,打开test.txt文件,发现文件没有内容n");
	Sleep(10000);
	printf("刷新缓冲区n");
	fflush(pf);//刷新缓冲区时,才将输出缓冲区的数据写到文件(磁盘)
	//注:fflush 在高版本的VS上不能使用了
	printf("再睡眠10秒-此时,再次打开test.txt文件,文件有内容了n");
	Sleep(10000);
	fclose(pf);
	//注:fclose在关闭文件的时候,也会刷新缓冲区
	pf = NULL;
	return 0;
}

刷新缓冲区会让缓冲区的内容写入磁盘里。

文件的打开和关闭

文件打开用fopen函数。
fopen函数会返回一个你想要打开的文件的指针,自己创建一个变量去接受就好了。

FILE* pf = fopen("文件名","打开方式");

文件关闭用fclose函数,传入对应文件的文件指针就可以了。

fclose(pf);

下面三个可以背一下,其他要用的时候查就好了。
很简单,不写例子了。

r:以只读的方式打开文本文件,文件必须存在;

w:以只写的方式打开文本文件,文件若存在则清空文件内容从文件头部开始写,若不存在则根据文件名创建新文件并只写打开;

a:以只写的方式打开文本文件,文件若存在则从文件尾部以追加的方式开始写,文件原来存在的内容不会清除(除了文件尾标志EOF),若不存在则根据文件名创建新文件并只写打开;

文件的顺序读写

大概有这么几个函数。

函数名 适用于
fgetc 所有输入流
fputc 所有输出流
fgets 所有输入流
fputs 所有输出流
fscanf 所有输入流
fprintf 所有输出流
fread 文件
fwrite 文件

在上面的几个函数中都出现了流(stream)这个概念,解释一下。
流是类的对象。

fgetc

fgetc是从任意输入流读取字符。

注:fgetc的返回值是int。

我们先测试从文件里面读取字符。

在桌面写了一个txt文件。

注:在写文件路径的时候,如果只写一个斜杠的话有可能出现转义字符。比如t等。再写一个斜杠防止转义就可以了。


我们再测试从屏幕上读入字符。
代码如下:

stdin是标准输入流。其实就是从屏幕上读取字符。

fputc

fputc和fgetc的用法是类似的。

向文件内写入字符


向标准输出流输出字符

fgets

fgets的用处是从输入流里面得到字符串。
但是它的使用方法有些奇怪。


如果你想得到5个字符,他只会返回4个字符给你,最后一个字符帮你变成斜杠0.

fputs

fputs的用处是把字符串写到输出流。

结果:

fscanf

fscanf的用处是格式化读取数据

格式化读取数据的意思就是任意数据类型你都可以读取。和scanf一样。只不过fscanf可以读取文件里面的数据。

对比一下fscanf和scanf两个函数,发现没什么区别,就是fscanf要多传一个文件指针而已。

struct S
{
	char ch;
	int i;
	char name[20];
};

	struct S s = { 0 };
	fscanf(pf, "%c %d %s", &(s.ch), &(s.i), s.name);
	printf("%c %d %s", s.ch, s.i, s.name);
	

fprintf

fprintf和fscanf的使用方法差不多。

	struct S s = { 'a',1,"zhangsan" };
	fprintf(pf,"%c %d %s",s.ch,s.i,s.name);

这样就可以往文件里面写你想要的东西了。

fwrite

fwrite是以二进制形式把内容写入文件里面。

struct S
{
	char ch;
	int i;
	char str[20];
};
int main()
{
	FILE* pf = fopen("C:\Users\86135\Desktop\test.txt", "wb");
	struct S s = { 'a',1,"zhangsan" };
	fwrite(&s, sizeof(struct S), 1, pf);
	return 0;
}

结果:

fread

fread是以二进制形式读取文件内容

struct S
{
	char ch;
	int i;
	char str[20];
};
int main()
{
	FILE* pf = fopen("C:\Users\86135\Desktop\test.txt", "rb");
	struct S s = { 0 };
	fread(&s, sizeof(struct S), 1, pf);
	printf("%c %d %s", s.ch, s.i, s.str);
	return 0;
}

结果:

sscanf和sprintf

有这么一道题目,对比一下下面三个函数。

scanf/fscanf/sscanf

printf/fprintf/sprintf
前面两个函数就不说了。sscanf和sprintf说一下。这两个函数很有意思

sprintf函数可以将任意类型的数据转换成字符串形式。

int main()
{
	struct S s = { 'a',1,"zhangsan" };
	char str[20] = { 0 };//用str来接收
	sprintf(str, "%c %d %s", s.ch, s.i, s.str);
	printf(str);//把str打印出来看一下
	return 0;
}

这个时候已经是字符串了。

sscanf的用法也类似。

	struct S s = { 'a',1,"zhangsan" };
	char str[20] = { 0 };
	sprintf(str, "%c %d %s", s.ch, s.i, s.str);
	
	//现在str里面已经存放了信息了。
	struct S s2 = { 0 };
	sscanf(str, "%c %d %s",&(s2.ch),&(s2.i),(s2.str));//两个参数的位置不要写反
	printf("%c %d %s", s2.ch, s2.i, s2.str);
文件的随机读写

文件的随机读写的意思就是可以调整文件指针的位置,进行任意位置的访问。

fseek


offset是偏移量的意思,origin是现在的位置。库里面定义了几个宏,如下:

原先文件里面放着abcdef。现在用fseek让pf指针往后移动一个位置。原先fgetc得到的应该是a,现在是b了。

int main()
{
	//文件里面存放的是abcdef
	FILE* pf = fopen("C:\Users\86135\Desktop\test.txt", "rb");
	fseek(pf, 1, SEEK_SET);
	int ch = fgetc(pf);
	printf("%cn", ch);
	return 0;
}
ftell


ftell可以告诉你当前指针的offsetof是多少。

	FILE* pf = fopen("C:\Users\86135\Desktop\test.txt", "rb");
	fseek(pf, 3, SEEK_SET);
	long offsetof = ftell(pf);
	printf("%dn", offsetof);

输出的是3.

rewind

rewind可以让文件指针重新回到文件开头。

	FILE* pf = fopen("C:\Users\86135\Desktop\test.txt", "rb");
	fseek(pf, 3, SEEK_SET);
	long offsetof = ftell(pf);
	printf("%dn", offsetof);
	rewind(pf);
	offsetof = ftell(pf);
	printf("%d", offsetof);

文件结束判定 ferror和feof

文件打开失败有几种可能,有可能是出现了错误,也有可能是遇到了文件结束符号eof。当文件打开失败的时候,我们要怎么判断是哪一个错误呢?

这时候我们就要使用ferror和feof了。如果ferror返回0,就是文件没有出错,即代表遇到了文件结束符号eof了。如果feof返回0,就是文件没有遇到eof,即代表文件出现了某些错误。

  1. 文本文件读取是否结束,判断返回值是否为EOF (fgetc),或者NULL(fgets)
    例如:
    fgetc判断是否为EOF.
    fgets判断返回值是否为NULL.
  2. 二进制文件的读取结束判断,判断返回值是否小于实际要读的个数。
    例如:
    fread判断返回值是否小于实际要读的个数。

下面这段代码能很好的说明问题。

int main()
{
    int c; // 注意:int,非char,要求处理EOF
    FILE* fp = fopen("test.txt", "r");
    if(!fp) {
        perror("File opening failed");
        return EXIT_FAILURE;
   }
 //fgetc 当读取失败的时候或者遇到文件结束的时候,都会返回EOF
    while ((c = fgetc(fp)) != EOF) // 标准C I/O读取文件循环
   { 
       putchar(c);
   }
 //判断是什么原因结束的
    if (ferror(fp))
        puts("I/O error when reading");
    else if (feof(fp))
        puts("End of file reached successfully");
    fclose(fp);
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/303170.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号