0
点赞
收藏
分享

微信扫一扫

C语言-文件操作函数基础+进阶标准输入流输出流

邯唐情感 04-01 09:31 阅读 2

学习的流程

————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

文件操作原理

——————————————————————————————————————————— 

为什么使用文件

——————————————————————————————————————————— 

什么是文件


——————————————————————————————————————————— 

二进制文件 和文本文件

二进制编译器的方式打开 二进制文件,二进制文件是我们不能直接看懂的文件

文本文件就是肉眼看得懂的

——————————————————————————————————————————— 

文件流

文件使用流程是,打开 读写 关闭

并且文件的使用是需要依靠媒介的,也就是流

就比如你需要开电视,你不可能是用手把电视打开,你还得跑过去,很麻烦,所以我们发明了遥控器,这个遥控器也就是中间媒介,不需要你大费周章的再去开电视,只需要遥控器一按,就打开了。

下面进行图解举例。

——————————————————————————————————————————— 

文件指针

因为需要流,所以需要文件指针 

在C语言中,文件操作是通过所谓的“流”来进行的,而文件指针就是这种流的抽象表示。FILE结构体是C标准库中定义的一个数据结构,它用于封装关于文件的信息和用于操作文件的数据。

文件指针通常是指向FILE结构体的指针变量,它用于表示一个打开的文件流。通过文件指针,您可以执行诸如读取、写入、定位和关闭文件等操作。

当您使用fopen函数打开一个文件时,它会返回一个FILE*类型的指针,这就是文件指针。然后,您可以使用这个指针来调用其他文件操作函数,如freadfwritefgetsfputsfprintf

FILE结构指针 称为文件指针 

今天我们讲的主要就是用FILE打开文件

在C语言中,`FILE`结构体定义在标准输入输出库`stdio.h`中,它用于表示一个打开的文件流。`FILE`结构体的定义如下:
```c
typedef struct _iobuf {
    int  _flag;         /* 文件状态标志 */
    char *_ptr;         /* 当前读/写的指针 */
    char *_base;        /* 缓冲区的基地址 */
    char *_end;         /* 缓冲区的结束地址 */
    /* 以下成员用于缓冲区管理 */
    void *_lock;        /* 用于文件锁 */
    struct _io_functions {
        int (*read) (struct _iobuf *, char *, int);
        int (*write) (struct _iobuf *, const char *, int);
        int (*seek) (struct _iobuf *, long int, int);
        int (*close) (struct _iobuf *);
        /* 可能还有其他函数指针 */
    } _functions;
    /* 以下成员用于系统特定的信息 */
    void *_data;        /* 用于存放系统特定的数据 */
} FILE;
```
这个结构体包含了多个用于文件操作的成员变量和函数指针。下面是这些成员的简要说明:
- `_flag`:这个整数成员用于存储文件的状态标志,如是否为末尾(`FEof`)、是否出错(`FError`)等。
- `_ptr`:这个指针成员指向当前读/写的文件位置。
- `_base`:这个指针成员指向缓冲区的开始位置,即文件数据的内存缓冲区。
- `_end`:这个指针成员指向缓冲区的结束位置。
- `_lock`:这个指针成员用于文件锁,它可以用于多线程环境中的同步。
- `_functions`:这个结构体成员包含了文件操作的函数指针,分别用于读取(`read`)、写入(`write`)、定位(`seek`)和关闭(`close`)文件。
- `_data`:这个指针成员用于存放系统特定的数据,通常用于实现特定的文件操作。
文件信息区通常指的是`FILE`结构体中用于存储文件信息和控制文件操作的这部分内容。这些信息包括文件的状态、当前的读写位置、缓冲区信息等。通过操作这些成员,可以实现对文件的读写和控制功能。

———————————————————————————————————————————

文件信息区

文件信息区 也就是FILE的类型

所以我们通过pf来维护 文件信息区的写和读

进行操作的时候 一定要通过文件指针变量找到与他关联的文件

———————————————————————————————————————————

文件的打开和关闭

使用

这里是如果有 也就是打开 没有也就是报错

r--只读

w--创建一个新文件(没有)

—————————————————————————————————————————— 

顺序读写函数的介绍

————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

读取文件方式 

 可以和fopen打开文件,配合使用

  • "r":只读模式,打开一个已经存在的文本文件。
  • "w":写入模式,打开一个文本文件用于写入。如果文件已经存在,则之前的内容会被删除。
  • "a":追加模式,打开一个文本文件用于写入。如果文件不存在,则会创建一个新文件。
  • "rb":只读模式,打开一个二进制文件。
  • "wb":写入模式,打开一个二进制文件用于写入。
  • "ab":追加模式,打开一个二进制文件用于写入

打开文件需要用流,也就是一个介质, 

————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

fopen(打开文件)和fclose(关闭文件)

 fopen` 和 `fclose` 是C语言中用于文件操作的两个基本函数。

fopen语法介绍

`fopen` 函数用于打开一个文件,并返回一个指向该文件的指针。如果打开文件失败,`fopen` 会返回 `NULL`。
函数原型:

```c
FILE *fopen(const char *path, const char *mode);
```

参数:
- `path`: 要打开的文件的路径。
- `mode`: 文件的打开模式(例如:`"r"` 读取模式,`"w"` 写入模式,`"a"` 追加模式等)。
返回值:

fopen参数介绍

如果成功,返回一个指向 `FILE` 对象的指针。
如果失败,返回 `NULL`。

—————————————————————————————————————————— 

fclose语法介绍

`fclose` 函数用于关闭由 `fopen` 函数打开的文件。在关闭文件后,相关的文件指针也会被清空,此后不能再使用该指针进行文件操作。
函数原型:

```c
int fclose(FILE *stream);
```

fclose参数介绍

- `stream`: 由 `fopen` 函数返回的文件指针。
返回值:
- 如果成功,返回 `0`。
- 如果出错,返回 `EOF`。

使用示例
下面是一个简单的使用 `fopen` 和 `fclose` 的例子:

```c
#include <stdio.h>
int main() {
    FILE *filePtr;
    char *filename = "example.txt";
    // 打开文件
    filePtr = fopen(filename, "r"); // 以读取模式打开文件
    if (filePtr == NULL) {
        perror("Error opening file");
        return -1;
    }
    // ... 在这里进行文件操作 ...
    // 关闭文件
    fclose(filePtr);
    filePtr=NULL;
    return 0;
}
```

在这个例子中,首先以读取模式(`"r"`)打开一个名为 `example.txt` 的文件。如果文件打开成功,我们就有了一个指向该文件的 `FILE` 类型的指针,可以用来读取文件内容。操作完成后,使用 `fclose` 函数关闭文件,释放系统资源。
在使用 `fopen` 和 `fclose` 进行文件操作时,应该始终检查 `fopen` 的返回值以确保文件是否成功打开,

1,并在操作完成后使用 `fclose` 关闭文件,以避免资源泄露和数据丢失。

2,在关闭文件之后让他指向空指针,防止因为是野指针而导致出错(因为这里本质还是指针,指针指向的文件关闭后,指向的是一个空的地址,所以此时也就变成了野指针,所以我们需要指向NULL,防止出现问题)

3,这两个函数没有详细介绍就说了一下语法格式的问题

————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

fputc(写入字符)

语法格式 

fputs(const char *str, FILE *stream):将一个字符串写入文件。

但是这里只能写入一个字符单次

——————————————————————————————————————————  

写进去a b c

——————————————————————————————————————————  

写进去a-z

读文件,这里需要打印的话需要读取文件,然后才能打印

代码,这这里补充说明一下,fputc函数的使用只能一次写一个字符,要么就是循环输入,并不能直接输入字符串

——————————————————————————————————————————  

 代码1写进去a

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdio.h>
int main()
{
	FILE* pf = fopen("text.txt", "w");
	if (pf == NULL)
	{
		perror("fopen:w:");
		return 1;
	}
	fputc('a', pf);


	fclose(pf);
	pf = NULL;
	return 0;
}

我们发现写进去是没有问题的

——————————————————————————————————————————  

代码2写进去字符串

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdio.h>
int main()
{
	FILE* pf = fopen("text.txt", "w");
	if (pf == NULL)
	{
		perror("fopen:w:");
		return 1;
	}
	fputc('a', pf);//我们预计写入a
	fputc('bcd', pf);//我们预计写入bcd


	fclose(pf);
	pf = NULL;
	return 0;
}

这里我们发现,这里不能输入字符串,还是只能输入一个字符

——————————————————————————————————————————  

代码3循环输入A-Z

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdio.h>
int main()
{
	FILE* pf = fopen("text.txt", "w");
	if (pf == NULL)
	{
		perror("fopen:w:");
		return 1;
	}
	//fputc('a', pf);
	//fputc('bcd', pf);
	for (int i = 'A'; i < 'Z'; i++)
	{
		fputc(i, pf);

	}


	fclose(pf);
	pf = NULL;
	return 0;
}

这里我们发现是可以的,但是一次只能输入一个字符,并且是连续输入的,这里我们可以知道,fputc输入字符是连续输入的

————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

fgetc(读字符) 

函数的语法格式 

语法格式getc函数是C语言中的标准库函数之一,用于从指定的文件流中逐个字符地读取字符。它的函数原型如下:

int fgetc(FILE *stream)

上面我们描述过函数需要

fopen(打开)+读取+打印

中间可能还有写入等等,但是基本上是步骤是这个步骤

—————————————————————————————————————————— 

函数的返回参数

getc函数正常读取结束返回的是读取到的字符值。返回值是int类型,范围是0到255,或者是EOF(-1),表示读取结束。 

-1 本质是整数 所以返回类型需要是整形

当你使用 fgetc 时,以下规则适用:

  1. 如果成功读取一个字符,fgetc 返回该字符的 ASCII 码值。在 ASCII 表中,控制字符(如换行符 \n、回车符 \r 等)和空格字符也有对应的数值。

  2. 如果读取遇到文件末尾(即文件中再也没有字符可以读取),fgetc 返回 EOF。在 C 标准库中,EOF 定义为 -1

  3. 如果读取失败(例如,文件指针无效或文件无法打开),fgetc 也会返回 EOF

请注意,fgetc 函数只能读取一个字符,而不是字符串。如果你需要读取多个字符,你需要循环调用 fgetc 或者使用其他函数如 fgets,后者可以读取一行文本。

——————————————————————————————————————————  

函数的读取方式

一个字符一个字符的读取

如果需要所有内容一起读取

那么你需要进行循环读取,读取的字符最好存起来,不等于eof 也就是继续循环,等于的时候也就是停止循环,写一个字符读取一个字符 写一堆字符 读取一堆字符。

—————————————————————————————————————————— 

代码1(单个读取)

当你使用 fgetc 时,以下规则适用:

如果成功读取一个字符,fgetc 返回该字符的 ASCII 码值。在 ASCII 表中,控制字符(如换行符 \n、回车符 \r 等)和空格字符也有对应的数值。

如果读取遇到文件末尾(即文件中再也没有字符可以读取),fgetc 返回 EOF。在 C 标准库中,EOF 定义为 -1。

如果读取失败(例如,文件指针无效或文件无法打开),fgetc 也会返回 EOF。

请注意,fgetc 函数只能读取一个字符,而不是字符串。如果你需要读取多个字符,你需要循环调用 fgetc 或者使用其他函数如 fgets,后者可以读取一行文本。
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdio.h>
int main()
{
	//打开文件并且写入
	FILE* pf = fopen("text.txt", "w");
	if (pf == NULL)
	{
		perror("fopen:w:");
		return 1;
	}

	//fputc('a', pf);
	//fputc('bcd', pf);
	//这里已经输入A-Z的字符
	for (int i = 'A'; i <= 'Z'; i++)
	{
		fputc(i, pf);

	}

	//int c = 0;
	//c = fgetc(pf);
	//printf("%c ", c);这里会发现不能读取成功并且打印出来
	fclose(pf);
	pf = NULL;






	//这里说明一下为什么需要进行二次打开文件,因为上面的是的写入,不是读取,所以需要关闭文件之后再进行读取
	// 如果你想要可以读取又可以写入,你也可以用a+,我这里主要是进行举例说明。
	//打开文件
	FILE* ps = fopen("text.txt", "r");
	if (ps == NULL)
	{
		perror("fopen:w:");
		return 1;
	}

	//单个进行读取 这里需要进行一个变量进行接收,因为这个函数的返回值是返回正确的情况下就会返回数值的ASCII码值,
	//读取不正确的情况就会返回eof 读取到末尾也会返回eof 所以我们需要用一个变量进行接收,你可以是char 也可以是int
	int ch = 0;
	ch =fgetc(ps);
	printf("%c ", ch);

	//循环一次进行读取 ,这里你可以用while,也可以用while

	fclose(ps);
	pf = NULL;
	return 0;
}


可以看到只是读取一个字符A 

—————————————————————————————————————————— 

代码2(循环读取)

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdio.h>
int main()
{
	//打开文件并且写入
	FILE* pf = fopen("text.txt", "w");
	if (pf == NULL)
	{
		perror("fopen:w:");
		return 1;
	}

	//fputc('a', pf);
	//fputc('bcd', pf);
	//这里已经输入A-Z的字符
	for (int i = 'A'; i <= 'Z'; i++)
	{
		fputc(i, pf);

	}

	//int c = 0;
	//c = fgetc(pf);
	//printf("%c ", c);这里会发现不能读取成功并且打印出来
	fclose(pf);
	pf = NULL;






	//这里说明一下为什么需要进行二次打开文件,因为上面的是的写入,不是读取,所以需要关闭文件之后再进行读取
	// 如果你想要可以读取又可以写入,你也可以用a+,我这里主要是进行举例说明。
	//打开文件
	FILE* ps = fopen("text.txt", "r");
	if (ps == NULL)
	{
		perror("fopen:w:");
		return 1;
	}

	//单个进行读取 这里需要进行一个变量进行接收,因为这个函数的返回值是返回正确的情况下就会返回数值的ASCII码值,
	//读取不正确的情况就会返回eof 读取到末尾也会返回eof 所以我们需要用一个变量进行接收,你可以是char 也可以是int
	int ch = 0;
	ch =fgetc(ps);
	printf("%c \n", ch);

	//循环一次进行读取 ,这里你可以用while,并且你这里可以发现 之前读取之后A后面进行读取的时候,只是读取A之后的字符
	//也就是我们只是读取一次
	int ca = 0;
	while ((ca = fgetc(ps)) != EOF)
	{
		printf("%c ", ca);
	}
	fclose(ps);
	pf = NULL;
	return 0;
}


——————————————————————————————————————————  

代码3(循环读取)

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdio.h>
int main()
{
	//打开文件并且写入
	FILE* pf = fopen("text.txt", "w");
	if (pf == NULL)
	{
		perror("fopen:w:");
		return 1;
	}

	//fputc('a', pf);
	//fputc('bcd', pf);
	//这里已经输入A-Z的字符
	for (int i = 'A'; i <= 'Z'; i++)
	{
		fputc(i, pf);

	}

	//int c = 0;
	//c = fgetc(pf);
	//printf("%c ", c);这里会发现不能读取成功并且打印出来
	fclose(pf);
	pf = NULL;






	//这里说明一下为什么需要进行二次打开文件,因为上面的是的写入,不是读取,所以需要关闭文件之后再进行读取
	// 如果你想要可以读取又可以写入,你也可以用a+,我这里主要是进行举例说明。
	//打开文件
	FILE* ps = fopen("text.txt", "r");
	if (ps == NULL)
	{
		perror("fopen:w:");
		return 1;
	}

	//单个进行读取 这里需要进行一个变量进行接收,因为这个函数的返回值是返回正确的情况下就会返回数值的ASCII码值,
	//读取不正确的情况就会返回eof 读取到末尾也会返回eof 所以我们需要用一个变量进行接收,你可以是char 也可以是int
	int ch = 0;
	ch =fgetc(ps);
	printf("%c \n", ch);

	//循环一次进行读取 ,这里你可以用while,并且你这里可以发现 之前读取之后A后面进行读取的时候,只是读取A之后的字符
	//也就是我们只是读取一次
	int ca = 0;
	//while ((ca = fgetc(ps)) != EOF)
	//{
	//	printf("%c ", ca);
	//}
	for (ca = fgetc(ps); fgetc(ps) != EOF; ca++)
	{
		printf("%c ", ca);
	}
	fclose(ps);
	pf = NULL;
	return 0;
}


这种循环方式也是可以的,但是很显然,这个还需要修改,有点麻烦,没有while循环好用,所以不详细说明了

————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

fputs(写入文本)

`fputs` 函数的语法

如下所示:

```c
int fputs(const char *str, FILE *stream);
```

这里的参数含义如下:
- `str`:这是一个指向要写入文件的 C 字符串的指针。字符串可以是任何以 null 字符 `'\0'` 结尾的字符序列。
- `stream`:这是一个指向 `FILE` 对象的指针,该对象标识了输出流,即文件或其他 I/O 设备。
函数返回值:
- 如果写入成功,`fputs` 返回 `str` 指针。
- 如果写入失败,`fputs` 返回 `EOF`。
`fputs` 函数会尝试将 `str` 指向的字符串写入到由 `stream` 指针指向的文件流中。写入操作会一直进行,直到遇到字符串末尾的 null 字符,或者在写入过程中发生错误。如果写入成功,`fputs` 函数会更新文件的位置指针。
下面是一个简单的例子,展示如何使用 `fputs` 函数将一个字符串写入到文件中:

```c
#include <stdio.h>
int main() {
    FILE *file;
    // 打开文件用于写入,如果文件不存在则创建它
    file = fopen("example.txt", "w");
    if (file == NULL) {
        perror("Error opening file");
        return 1;
    }
    // 使用 fputs 写入字符串
    fputs("Hello, World!", file);
    // 关闭文件
    fclose(file);
    return 0;
}
```

———————————————————————————————————————————
在这个例子中,`fputs` 函数会写入 "Hello, World!" 到 "example.txt" 文件中。如果文件已经存在,它的内容将被这个字符串覆盖;如果文件不存在,它将被创建。写入完成后,文件将被关闭。 

写到一行上面去

除非两个主动加上换行\n

———————————————————————————————————————————

代码1单个输入

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdio.h>
//写入字符串
int main()
{
	FILE* pf = fopen("text.txt", "w");
	if (pf == NULL)
	{
		perror("foopen:w:");
		return 1;
	}
	fputs("hellow word", pf);
	fputs("你好世界", pf);
	fclose(pf);//关闭
	pf = NULL;//防止成为野指针,置为空指针
	return 0;
}

这里我们可以发现,我们不仅可以写入字符串,还可以写入文本

—————————————————————————————————————————— 

代码2循环输入

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdio.h>
//写入字符串
int main()
{
	//写入文件
	FILE* pf = fopen("text.txt", "w");
	if (pf == NULL)
	{
		perror("foopen:w:");
		return 1;
	}
	fputs("hellow word", pf);
	fputs("你好世界", pf);
	for (int i = 0; i < 10; i++)
	{
		fputs("hellow 世界\n", pf);//这里采取换行符,进行换行

	}
	fclose(pf);//关闭
	pf = NULL;


	return 0;
}

————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

fgets(读取文本)

语法格式

`fgets` 函数用于从文件读取一行文本。其语法如下:

```c
char *fgets(char *str, int n, FILE *stream);
```

这里的参数含义如下:
- `str`:这是一个指向字符数组的指针,用于存储从文件中读取的一行文本。
- `n`:这是一个整数,表示 `str` 数组的最大长度(以字符为单位)。
- `stream`:这是一个指向 `FILE` 对象的指针,该对象标识了输入流,即文件或其他 I/O 设备。
函数返回值:
- 如果读取成功,`fgets` 返回 `str` 指针。
- 如果读取失败,`fgets` 返回 `NULL`。
`fgets` 函数会从由 `stream` 指针指向的文件流中读取最多 `n-1` 个字符(因为最后一个字符是为了放置字符串结束符 `'\0'` 而保留的),并将它们存储在 `str` 指向的字符数组中。读取操作会一直进行,直到读取到换行符、文件结束符或发生错误。读取到的字符串末尾会自动加上 null 字符 `'\0'`。
下面是一个简单的例子,展示如何使用 `fgets` 函数从文件中读取一行文本:

```c
#include <stdio.h>
int main() {
    FILE *file;
    char line[100]; // 创建一个足够大的数组来存储一行文本
    // 打开文件用于读取
    file = fopen("example.txt", "r");
    if (file == NULL) {
        perror("Error opening file");
        return 1;
    }
    // 使用 fgets 读取一行文本
    if (fgets(line, sizeof(line), file) != NULL) {
        printf("Read line: %s\n", line);
    } else {
        printf("Failed to read line.\n");
    }
    // 关闭文件
    fclose(file);
    return 0;
}
```

在这个例子中,`fgets` 函数会读取 "example.txt" 文件中的一行文本,并将其存储在 `line` 数组中。然后,程序会打印出读取到的文本。

如果文件中的文本超过 `line` 数组的大小,那么超出部分将不会被读取,并且 `fgets` 函数仍然会成功返回。如果文件已经到达文件末尾,`fgets` 函数会读取到空字符串并返回 `NULL`。

——————————————————————————————————————————— 

-1 本质是整数 所以返回类型需要是整形

读取方式

一个字符一个字符的读取

所有内容一起读取

循环读取

读取的字符最好存起来

不等于eof 也就是继续循环

等于的时候 也就是停止循环

写一个字符读取一个字符 写一堆字符 读取一堆字符

———————————————————————————————————————————

读取函数的返回参数

fgetc

如果读取正常,返回的是读取到字符的ASCII码值

如果读取的过程中遇到文件末尾,或者发生错误,就返回EOF
fgets
如果读取正常,返回的是存储读取到的字符串的字符数组的地址
 

如果读取的过程中遇到文件末尾,或者发生错误,返回NULL 

———————————————————————————————————————————

代码1不是循环读取文本

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdio.h>
//写入字符串
int main()
{
	//写入文件
	FILE* pf = fopen("text.txt", "w");
	if (pf == NULL)
	{
		perror("foopen:w:");
		return 1;
	}
	fputs("hellow word", pf);
	fputs("你好世界", pf);
	for (int i = 0; i < 10; i++)
	{
		fputs("hellow 世界\n", pf);
	}
	fclose(pf);//关闭
	pf = NULL;

	//读取文件
	//重申一遍,文件只有读取之后才能打印出来
	FILE* ps = fopen("text.txt", "r");
	if (ps == NULL)
	{
		perror("fopen:r:");
		return 1;
	}
	//不是循环读取文件
	char arr[1000] = { 0 };
	fgets(arr, 100, ps);
	printf("%s  ", arr);

	fclose(ps);//关闭文件
	ps = NULL;

	return 0;
}

这里特地我给出100字节,当然的读取不完的,这里说明单次读取只能读取一行

循环读取可以不遇见NULL之前可以读取全部 

———————————————————————————————————————————

代码2循环读取文本

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdio.h>
//写入字符串
int main()
{
	//写入文件
	FILE* pf = fopen("text.txt", "w");
	if (pf == NULL)
	{
		perror("foopen:w:");
		return 1;
	}
	fputs("hellow word", pf);
	fputs("你好世界", pf);
	for (int i = 0; i < 10; i++)
	{
		fputs("hellow 世界\n", pf);

	}
	fclose(pf);//关闭
	pf = NULL;

	//读取文件
	//重申一遍,文件只有读取之后才能打印出来
	FILE* ps = fopen("text.txt", "r");
	if (ps == NULL)
	{
		perror("fopen:r:");
		return 1;
	}
	//循环读取
	//这里循环读取的需要知道的是,只要是循环读取,其实不管是多少字符读取,其实最后都会读取出来
	//因为你没有遇见,NULL说明你的文本没有读取完毕,如果你是一次直到读取100字符,那么就会一次读取100字符直到读取完毕遇见NULL
	char arr[1000] = { 0 };//这里是字符串 或者长的文本,所以接收的时候,需要给一个数组,不能给一个变量     
	while (fgets(arr, 100, ps) != NULL)
	{
		printf("%s ", arr);
	}
	fclose(ps);//关闭文件
	ps = NULL;

	return 0;
}

这里特地我给出100字节,当然的读取不完的,这里说明单次读取只能读取一行

循环读取可以不遇见NULL之前可以读取全部

————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

fprintf(指定的格式写到文件里面适用于所有的输出流,可以打印在屏幕上面)+fscanf(指定的格式读取出来,适用于所有的输入流

 fprintf(指定的格式写到文件里面)

两个函数是一样的

打开文件

写文件 fprintf以指定的格式写到信息里面

同时这里是文本的形式写进去的 因为我们都读得懂

代码

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
struct MyStruct
{
	char name[20];
	int age;
};
int main()
{
	struct MyStruct s = { "张三",23 };
	FILE* ps = fopen("fprintf.txt", "w");//这里我们进行写入一个文件,没有的话会自动创建一个文件
	if (ps == NULL)
	{
		perror("fopen:w:");
		return 1;
	}
	fprintf(ps, "%s %d", s.name, s.age);//以指定格式写入文件
	fclose(ps);//关闭文件
	ps = NULL;//指针指向空指针


	return 0;
}

—————————————————————————————————————————— 

fscanf(指定的格式读取出来,适用于所有的输入流

同理这个和scanf是一样的

数组名本身就是地址

fscanf

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
struct MyStruct
{
	char name[20];
	int age;
};
int main()
{
	struct MyStruct s = { "张三",23 };
	FILE* ps = fopen("fprintf.txt", "w");
	if (ps == NULL)
	{
		perror("fopen:w:");
		return 1;
	}
	//这里是把内容写到文件里面
	fprintf(ps, "%s %d", s.name, s.age);//写入文件
	fclose(ps);
	ps = NULL;


	//只读,因为你剩下的操作是文件读取,所以这里不行w,但是可以是只读,读取文件
	FILE* pf = fopen("fprintf.txt", "r");
	if (pf == NULL)
	{
		perror("fopen:r:");
		return 1;
	}
	//这里是读取内容,不读取是无法直接打印文件内容的
	fscanf(pf, "%s %d", s.name, &(s.age));//数组首元素就是地址 不需要取地址 ,此时也就是读取成功

	printf("%s %d\n", s.name, s.age);//表纯输出流打印文件

	fprintf(stdout, "%s %d\n", s.name, s.age);//指定输出流,打印文件
	fclose(pf);
	pf = NULL;

	return 0;
}

———————————————————————————————————————————

fprintf(可以打印在屏幕上面

适用于所有的输出流,可以打印在屏幕上面

也就是你可以用fprintf写写入里面,用fscanf进行读取,再用fprintf进行打印

当然这里前面的参数是文件,我们指向的是文件,然后才能打印出来

stdout(补充说明)

stdout 是 C 标准库中的一个文件流,代表标准输出。标准输出通常指的是计算机屏幕,但它也可以被重定向到其他地方,比如一个文件。在 C 语言中,stdout 用于打印程序的输出信息,比如 printf 函数和 fprintf 函数输出的内容。

当你调用 printf 或者 fprintf 函数时,如果不指定文件指针参数,这些函数会默认使用 stdout 作为输出目标。例如:

printf("Hello, World!");

这行代码会将在 stdout 上打印 "Hello, World!"。默认情况下,stdout 指向控制台(屏幕),所以你会在屏幕上看到输出。

你还可以将 stdout 重定向到文件。例如,你可以使用系统命令行将输出重定向到文件:

./program > output.txt

这会使得 program 程序的标准输出被重定向到 output.txt 文件,而不会在屏幕上显示任何内容。

在 C 程序中,你也可以显式地将输出写入 stdout:

fprintf(stdout, "This will go to the screen or a file if redirected.\n");

因为这个不是标准输出流,是指定输出流,所以我们可以指定格式。

这里我们发现我们可以用fprintf函数打印出来

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
struct MyStruct
{
	char name[20];
	int age;
};
int main()
{
	struct MyStruct s = { "张三",23 };
	FILE* ps = fopen("fprintf.txt", "w");
	if (ps == NULL)
	{
		perror("fopen:w:");
		return 1;
	}
	//这里是把内容写到文件里面
	fprintf(ps, "%s %d", s.name, s.age);//写入文件
	fclose(ps);
	ps = NULL;


	//只读,因为你剩下的操作是文件读取,所以这里不行w,但是可以是只读,读取文件
	FILE* pf = fopen("fprintf.txt", "r");
	if (pf == NULL)
	{
		perror("fopen:r:");
		return 1;
	}
	//这里是读取内容,不读取是无法直接打印文件内容的
	fscanf(pf, "%s %d", s.name, &(s.age));//数组首元素就是地址 不需要取地址 

	printf("%s %d\n", s.name, s.age);//表纯输出流打印文件

	fprintf(stdout, "%s %d\n", s.name, s.age);//指定输出流,打印文件
	fclose(pf);
	pf = NULL;

	return 0;
}

————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

sprintf(指定格式转化成字符串)+sscanf(字符串转化成指定格式)

sprintf(指定格式转化成字符串)

格式化的数据转化成字符串sprintf

sprintf 是一个在 C 语言中定义的函数,它的作用是将格式化的字符串和参数转换成字符串,并将结果存储在指定的字符数组中。因此,sprintf 可以用来将文件中的文档内容转化成字符串,也可以用来将刚编写的结构体代码转化为字符串。具体使用方式取决于程序的具体需求。 

这里已经转化为字符串

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
struct MyStruct
{
	char name[20];
	int age;
};
int main()
{
	struct MyStruct s = { "张三",23 };
	FILE* ps = fopen("fprintf.txt", "w");
	if (ps == NULL)
	{
		perror("fopen:w:");
		return 1;
	}
	//这里是把内容写到文件里面
	fprintf(ps, "%s %d", s.name, s.age);//写入文件
	fclose(ps);
	ps = NULL;


	//只读,因为你剩下的操作是文件读取,所以这里不行w,但是可以是只读,读取文件
	FILE* pf = fopen("fprintf.txt", "r");
	if (pf == NULL)
	{
		perror("fopen:r:");
		return 1;
	}
	//这里是读取内容,不读取是无法直接打印文件内容的
	fscanf(pf, "%s %d", s.name, &(s.age));//数组首元素就是地址 不需要取地址 

	//转化为字符串的形式
	char buf[100] = { 0 };//因为是转化成字符串的形式,所以需要用一个数组进行接收
	sprintf(buf, "%s %d", s.name, s.age);
	printf("字符串打印:  %s \n", buf);
    
    fclose(pf);
	pf = NULL;

	return 0;
}

———————————————————————————————————————————

sscanf(字符串转化成指定格式)

sscanf语法说明

这里是 从结构体读取数据

这里是从buf里面读取

所以sscanf也就是前面加上一个需要读取的名称

两次打印的对比,一样的,但是此时已经不是字符串的格式已经是指定的格式了

 代码总结

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
struct MyStruct
{
	char name[20];
	int age;
};
int main()
{
	struct MyStruct s = { "张三",23 };
	FILE* ps = fopen("fprintf.txt", "w");
	if (ps == NULL)
	{
		perror("fopen:w:");
		return 1;
	}
	//这里是把内容写到文件里面
	fprintf(ps, "%s %d", s.name, s.age);//写入文件
	fclose(ps);
	ps = NULL;


	//只读,因为你剩下的操作是文件读取,所以这里不行w,但是可以是只读,读取文件
	FILE* pf = fopen("fprintf.txt", "r");
	if (pf == NULL)
	{
		perror("fopen:r:");
		return 1;
	}
	//这里是读取内容,不读取是无法直接打印文件内容的
	fscanf(pf, "%s %d", s.name, &(s.age));//数组首元素就是地址 不需要取地址 

	//转化为字符串的形式
	char buf[100] = { 0 };//因为是转化成字符串的形式,所以需要用一个数组进行接收
	sprintf(buf, "%s %d", s.name, s.age);
	printf("字符串打印:  %s \n", buf);

	//字符串转化为带有格式的形式
	sscanf(buf, "%s %d", s.name, &(s.age));//我们这里还是这个格式, 把数组转化成格式给到结构体里面
	fprintf(stdout, "按照格式打印:%s %d\n", s.name, s.age);//指定输出流,打印文件
	fclose(pf);
	pf = NULL;

	return 0;
}

 sscanf(buf, "%s %d", s.name, &(s.age));//我们这里还是这个格式, 把数组转化成格式给到结构体里面,buf是字符串,格式化的输入到结构体里面

———————————————————————————————————————————

下面这个是把bit格式化的读取到buf里面 ,简单的说也就是后面放置的是可以接收的一个空的空间、

————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

printf(标准输出流)+scanf(标准输入流)+函数的总结

这里说明一下,printf和scanf经常使用,就不详细举例,直接进行说明。

在C语言中,printf、fprintf、sprintf、scanf、sscanf和fscanf是用于输入和输出数据的函数。下面是它们的区别和通常的使用场景:

  1. printf
    • printf函数用于将格式化的数据输出到标准输出(通常是终端或控制台)。
    • 它不会在输出字符串的末尾添加换行符,所以如果需要换行,需要在格式字符串中显式包含\n。
    • 示例:printf("Hello, World!\n"
  1. fprintf
    • fprintf函数用于将格式化的数据输出到任意指定的文件指针(FILE *)。
    • 它可以将数据输出到文件、网络流等。
    • 示例:FILE *fp = fopen("file.txt", "w"); fprintf(fp, "Hello, World!\n"); fclose(fp);
  1. sprintf
    • sprintf函数用于将格式化的数据输出到一个字符数组或字符串。简单的说就是转化成字符串格式
    • 它不会在输出字符串的末尾添加换行符。
    • 示例:char buffer[100]; sprintf(buffer, "Hello, World!\n"); printf("%s", buffer);

  1. scanf
    • scanf函数用于从标准输入(通常是键盘)读取格式化的数据。
    • 它等待用户输入,并根据指定的格式解析输入的数据。
    • 示例:int num; scanf("%d", &num); printf("You entered: %d\n", num);
  1. sscanf
    • sscanf函数用于从字符串中读取格式化的数据。可以把字符串转化为任何你需要的格式
    • 它将字符串中的数据按照指定的格式解析成变量。
    • 示例:char str[] = "1234"; int num; sscanf(str, "%d", &num); printf("You entered: %d\n", num);
    • 可以把字符串转化为任何你需要的格式
  1. fscanf
    • fscanf函数用于从任意指定的文件指针读取格式化的数据。
    • 它可以从文件、网络流等读取数据。
    • 示例:FILE *fp = fopen("file.txt", "r"); int num; fscanf(fp, "%d", &num); fclose(fp); printf("You entered: %d\n", num);

格式化的数据就是带有格式的数据

比如整形 字符 浮点型

看到结构体不方便 需要转化为字符串 那就是 sprintf

需要转化回来 那就用sscanf, fscanf

————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

fwrite(二进制形式写进去,写wb)

语法格式

在 C 语言中,`fwrite()` 函数用于向文件写入数据。它的语法格式如下:

```c
size_t fwrite(const void *ptr, size_t size, size_t count, FILE *stream);
```

参数说明

1. `ptr`:必需。指向要写入数据的指针。(内容)(arr)
2. `size`:必需。每个数据项的大小(以字节为单位)。(大小)(sizeof(arr[0]))
3. `count`:必需。要写入的数据项的数量。(写入的长度)(sz)
4. `stream`:必需。文件指针,指向目标文件。(写入的目标文件)(pf)

返回值:
- 成功时,返回写入的字节数。
- 出错时,返回 `EOF`。
示例代码:

```c
#include <stdio.h>
int main() {
    FILE *fp;
    char str[] = "Hello, World!";
    size_t len = strlen(str);
    
    fp = fopen("example.txt", "w"); // 打开文件用于写入
    if (fp == NULL) {
        perror("Error opening file");
        return 1;
    }
    
    size_t written = fwrite(str, sizeof(char), len, fp); // 写入字符串
    if (written != len) {
        perror("Error writing to file");
    }
    
    fclose(fp); // 关闭文件
    return 0;
}
```

在这个示例中,我们打开了一个名为 "example.txt" 的文件,然后尝试将字符串 "Hello, World!" 写入该文件。`fwrite()` 函数返回实际写入的字节数,我们可以将其与要写入的字符串长度进行比较,以检查是否写入成功。如果写入失败,将通过 `perror` 函数打印错误信息。最后,我们关闭文件并返回。

———————————————————————————————————————————

fwrite(地址,一个元素多大,几个元素,写到哪个流里面)

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
	FILE* pf = fopen("二进制文件的操作", "wb");
	if (pf == NULL)
	{
		perror("二进制打开错误:wb:");
		return 1;
	}
	int arr[] = { 1,2,3,4,5,6,7,8,9,0,12,3,123,123,1,23,231,123,123,312,123,213 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	fwrite(arr, sizeof(arr[0]), sz, pf);
	fclose(pf);
	pf == NULL;
	return 0;
}

这里我们可以看到我们把二进制的文件写到里面去了 

这个函数只要记着

fwrite(地址,一个元素多大,几个元素,写到哪个文件里面)

————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

fread(读取二进制文件)

语法格式 

说明 

`fread()` 函数是 C 语言标准库中的一个函数,用于从文件指针指向的文件中读取数据。它定义在 `<stdio.h>` 头文件中。`fread()` 函数用于读取二进制文件,因为它的读取操作不会转换字符,即读取的字节序列与存储在文件中的序列完全一致。
`fread()` 函数的语法格式如下:

```c
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
```

参数说明:

- `void *ptr`: 指向要读取数据的内存块的指针。函数将从文件读取的数据存储到这个指针指向的内存块中。
- `size_t size`: 每个数据项的大小(以字节为单位)。
- `size_t nmemb`: 要读取的数据项的数量。
- `FILE *stream`: 指向 `FILE` 对象的指针,该 `FILE` 对象标识了要读取的文件。
`fread()` 函数返回读取的字节总数,如果读取失败或到达文件末尾,它可能返回 EOF。
示例代码:

```c
#include <stdio.h>
int main() {
    FILE *fp;
    int data;
    int itemsRead;
    fp = fopen("data.bin", "rb"); // 打开文件用于二进制读取
    if (fp == NULL) {
        perror("Error opening file");
        return -1;
    }
    // 分配足够的内存来存储一个整数
    data = (int)malloc(sizeof(int));
    itemsRead = fread(data, sizeof(int), 1, fp); // 读取一个整数
    if (itemsRead == 1) {
        printf("Read data: %d\n", *data);
    } else {
        printf("Failed to read data\n");
    }
    fclose(fp);
    free(data);
    return 0;
}


在上面的代码中,`fread()` 函数被用来从名为 "data.bin" 的文件中读取一个整数。这段代码假设文件中只有一个整数,并且使用 `malloc()` 分配了足够的内存来存储这个整数。读取完成后,代码打印出读取的整数值。记得在读取文件后关闭文件流,使用 `fclose()` 函数可以做到这一点。同时,使用 `free()` 函数释放用 `malloc()` 分配的内存是很重要的,以避免内存泄漏。 

———————————————————————————————————————————

代码图解 

版本1 

返回值参数是成功读取的元素

就是你让我读取100个 实际文件里面只有5个 那我只能读取5个 并且打印 

循环读取 这个打印出来也是12345

版本2 

这里是i++等于存到arr里面去了,也就是实际你打印出的是arr,也就是不存在最后指针指向的位置跑到后面,导致空间无法释放

while里面取地址取出的是首元素的地址,pf指向的文件放到了arr里面,所以才说,这里++,实际上,++的是arr数组里面的元素,因为arr已经接收了元素。剩下的就是打印

但是这里还是一个问题就是,不管你读取多少元素,最后都会把arr可以放下的所有的元素进行读取。

 代码总结

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
	FILE* pf = fopen("二进制文件的操作", "wb");//wb写入二进制文件
	if (pf == NULL)
	{
		perror("二进制打开错误:wb:");
		return 1;
	}
	int arr[] = { 1,2,3,4,5,6,7,8,9,0,12,3,123,123,1,23,231,123,123,312,123,213 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	fwrite(arr, sizeof(arr[0]), sz, pf);
	fclose(pf);
	pf == NULL;


	int str[1000] = { 0 };
	FILE* ps = fopen("二进制文件的操作", "rb");//rb读二进制文件
	if (ps == NULL)
	{
		perror("二进制打开错误:wb:");
		return 1;
	}
	//也就是
	//存储的地方,单个大小,读取大小,文件流
	fread(str, sizeof(int), 400, ps);//以字节为单位 40个字节也就是10个整形
	for (int i = 0; i < 100; i++)
	{
		printf("%d ", str[i]);
	}
	fclose(ps);
	ps == NULL;
	return 0;
}

超出读取范围,那么就会读取0字节,也就是后面的地址 ,但是我们并没有利用,所以才没有出问题,是不建议这样的,这里只是举例。

————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

fseek(根据文件偏移位置读取文件)

语法说明 

 `fseek` 函数是 C 语言标准库中的一个函数,用于在文件指针指向的流中设置读/写位置。其语法格式如下:

```c
#include <stdio.h>
int fseek(FILE *stream, long offset, int origin);
```

参数说明如下:

  `FILE *stream`:指向 `FILE` 对象的指针,该 `FILE` 对象标识了要进行操作的流。
- `long offset`:表示要移动的位数。如果 `offset` 是正数,则文件读/写位置向前移动 `offset` 字节;如果是负数,则向后移动。
- `int origin`:表示 `offset` 的起始点,可以是以下三个常量之一:
  - `SEEK_SET`:从文件的开头开始计算 `offset`(默认值)。
  - `SEEK_CUR`:从当前的文件读/写位置开始计算 `offset`。
  - `SEEK_END`:从文件的末尾开始计算 `offset`。

该函数执行成功时返回 `0`,失败时返回 `-1`。如果发生错误,可以通过 `ferror` 函数检查流是否出错。
请注意,`fseek` 函数对二进制文件和文本文件都是有效的。但是在文本文件中,由于需要考虑字符编码和换行符等因素,`fseek` 可能不会按照预期工作,特别是在不同平台之间移植代码时。

———————————————————————————————————————————

首先我们得有一个概念,读取文件需要有一个接收值。

fseek文件的当前位置SEEK_SET

SEEK_END倒着往前偏移

这几个都是找到f

代码

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
int main()
{
	FILE* pf = fopen("text.txt", "r");
	if (pf == NULL)
	{
		perror("ofpen:r:");
		return 1;
	}
	int ret = 0;
	fseek(pf, 4, SEEK_SET);//起始位置
	ret = fgetc(pf);
	printf("%c ", ret);

	fseek(pf, 4, SEEK_CUR);//文件指针当前位置
	ret = fgetc(pf);
	printf("%c ", ret);

	fseek(pf, -9, SEEK_END);//文件末尾开始计算,所以这里是负数,从后往前计算
	ret = fgetc(pf);
	printf("%c ", ret);

	fclose(pf);
	pf == NULL;
	return 0;
}

这个函数的目的不是进行打印而是找到偏移量,那么此时就可以进行读取到你需要的数值

比如你可以读取从前往后第3个字节那一个字节,那么你就可以使用这个函数,并且使用读取一个字节的函数打印出来。

如果你需要的是,从前往后第三个字节之后的字节,那么你就可以使用这个函数,配套使用读取函数,进行循环读取打印即可。

————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

rewind(回到起始位置)

语法格式 

在 C 语言中,`rewind` 函数用于将文件指针定位到文件的开头。它的语法格式如下:

```c
#include <stdio.h>
rewind(FILE *stream);
```

参数

`stream` 是指向 `FILE` 对象的指针,该对象标识了要重置的文件流。调用 `rewind` 函数后,文件流的位置指针将被重置到文件的开头,就像在使用 `fseek(stream, 0, SEEK_SET)` 一样。
下面是一个使用 `rewind` 的例子:

```c
#include <stdio.h>
int main() {
    FILE *fp;
    char buffer[100];
    fp = fopen("example.txt", "r"); // 打开文件
    if (fp == NULL) {
        // 处理错误
    }
    fread(buffer, sizeof(char), 100, fp); // 读取文件内容
    rewind(fp); // 将文件指针重置到文件开头
    fread(buffer, sizeof(char), 100, fp); // 重新读取文件内容
    fclose(fp); // 关闭文件
    return 0;
}
```

在这个例子中,`rewind` 函数被用来在读取文件内容后,将文件指针倒回到文件的开头,以便可以再次读取文件的内容。 

———————————————————————————————————————————

此时读取到f

我们可以用rewind回到起始位置

也就是直接输入文件流,就可以直接回到函数所在的起始位置

代码

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
int main()
{
	FILE* pf = fopen("text.txt", "r");
	if (pf == NULL)
	{
		perror("ofpen:r:");
		return 1;
	}
	int ret = 0;
	fseek(pf, 4, SEEK_SET);//起始位置
	ret = fgetc(pf);
	printf("%c ", ret);

	fseek(pf, 4, SEEK_CUR);//文件指针当前位置
	ret = fgetc(pf);
	printf("%c ", ret);

	fseek(pf, -9, SEEK_END);//文件末尾开始计算,所以这里是负数,从后往前计算
	ret = fgetc(pf);
	printf("%c \n", ret);

	rewind(pf);//配合使用,返回文件起始位置
	ret = fgetc(pf);
	printf("返回起始位置:%c ", ret);

	fclose(pf);
	pf == NULL;
	return 0;
}

————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

ftell(获取当前位置)

语法格式

在 C 语言中,`ftell` 函数用于获取当前文件指针的位置,以字节为单位。它的语法格式如下:

```c
#include <stdio.h>
long ftell(FILE *stream);
```

参数

`stream` 是指向 `FILE` 对象的指针,该对象标识了要查询位置的文件流。函数返回当前文件指针的位置,如果出错,则返回 `-1`。
下面是一个使用 `ftell` 的例子:

```c
#include <stdio.h>
int main() {
    FILE *fp;
    long position;
    char buffer[100];
    fp = fopen("example.txt", "r"); // 打开文件
    if (fp == NULL) {
        // 处理错误
    }
    fread(buffer, sizeof(char), 100, fp); // 读取文件内容
    position = ftell(fp); // 获取当前文件指针的位置
    printf("当前文件指针的位置是:%ld\n", position);
    fclose(fp); // 关闭文件
    return 0;
}
```

在这个例子中,`ftell` 函数被用来获取在读取文件内容后,文件指针当前位置的信息。然后,这个位置被打印出来。请注意,`ftell` 的返回值是一个 `long` 类型的值,因此它可以表示非常大的数字,这取决于文件的大小。 

———————————————————————————————————————————

ftell 函数是C语言标准库中的一个函数,用于获取当前文件位置指针的位置。这个位置是一个长整型数,表示从文件开始的字节偏移量。

换句话说,ftell 可以告诉你当前读/写文件的位置在哪里,这对于确定文件中某个特定位置的读/写操作非常有用。

函数原型定义如下:

long ftell(FILE *stream);

其中 stream 是指向 FILE 对象的指针,该 FILE 对象标识了要查询的流。

使用 ftell 函数时,可以进行以下操作:

  1. 确定当前的文件位置。
  2. 在读取或写入文件后,检查位置是否如预期。
  3. 在处理大文件时,可以利用 ftell 来判断是否已经到达文件末尾。

请注意,ftell 返回的值是在调用 fseek 之前或与之关联的文件操作之后的文件位置。如果在 ftell 之后对文件进行任何操作(如读取、写入或定位),则返回的值将不再准确。

在使用 ftell 时,还应当注意平台的差异,因为 ftell 的行为可能会受到操作系统和文件系统的影响。

从前到后用于获取当前文件位置指针的位置。这里是9,这里返回的是文件的偏移量

代码

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
int main()
{
	FILE* pf = fopen("text.txt", "r");
	if (pf == NULL)
	{
		perror("ofpen:r:");
		return 1;
	}
	int ret = 0;
	fseek(pf, 4, SEEK_SET);//起始位置
	ret = fgetc(pf);
	printf("%c ", ret);

	fseek(pf, 4, SEEK_CUR);//文件指针当前位置
	ret = fgetc(pf);
	printf("%c ", ret);

	fseek(pf, -9, SEEK_END);//文件末尾开始计算,所以这里是负数,从后往前计算
	ret = fgetc(pf);
	printf("%c \n", ret);

	rewind(pf);//配合使用,返回文件起始位置
	ret = fgetc(pf);
	printf("返回起始位置:%c \n", ret);

	int s = 0;//这里需要进行一个返回值进行接收
	s=ftell(pf);//这里我们已经知道返回了初始位置
	printf("当前位置:%d \n", s);//所以当前位置是1



	//此时神奇的来了,上面我们已经返回文件初始位置了,我们可以根据偏移量读取位置
	//因为是从前往后计算当前位置的,同时利用fseek函数把数值移动到最后一位,并且不进行偏移
	fseek(pf, 0, SEEK_END);//文件末尾开始计算,不进行偏移
	int a = 0;
	a = ftell(pf);
	printf("文件总长度:%d \n", a);


	fclose(pf);
	pf == NULL;
	return 0;
}

可以计算文件总的长度

————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

feof(文件读取结束的判定) 

语法格式 

`feof` 函数用于在文件读取操作中判断是否到达文件末尾。如果到达文件末尾,则返回非零值;否则返回零。
语法格式如下:

```c
#include <stdio.h>
int feof(FILE *stream);
```

参数

`stream` 是指向 `FILE` 对象的指针,该 `FILE` 对象标识了要检查的流。通常,这个参数是通过 `fopen` 函数返回的。
函数返回值:
- 如果已到达流 `stream` 的文件末尾,则返回非零值。
- 如果 `stream` 未打开或不是一个有效文件流,则行为未定义。
- 如果没有到达文件末尾,则返回零。

在使用 `feof` 函数时,通常与读取操作配合使用,例如 `fread` 或 `fgets`,以检查是否在读取过程中到达文件末尾。 

简单的说 是来根据返回值来进行判断的

fgetc 在读取到文件末尾时会返回 EOF,这可以通过比较 ch 和 EOF 来判断是否到达文件末尾。在大多数实现中,EOF 是一个非零值

———————————————————————————————————————————

feof文件读取结束的判定

这个不是判断文件是不是结束 是已经结束判断的原因是什么

是结束了 ?还是出错了?

如果是 正常读取结束那么就会进行判定,走if

如果不是正常读取结束,那么此时就会走else

从而打印出错误信息

不要用错了

也就是判断返回值是不是空指针

———————————————————————————————————————————

总结

文本文件

非零 就是正常的

———————————————————————————————————————————

错误的文件描述

也就是返回eof是非零值,也就是符合条件为真

否则为假,不满足条件,打印错误信息

———————————————————————————————————————————

做题 

————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

文件缓冲区 

设置缓冲区的目的就是提高效率

举例子来说的话 就是问老师问题,全班70人 ,每个人都要问,一会一个一会一个,那老师说了,你这样存五个问题再来。大家都可以问问题了。


这个代码可以感受到缓冲区的存在

刷新的意义是把缓冲区的文件放到内存里面去

———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— 

文件操作函数的综合使用 (例题)

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
int main()
{
	//创建打开文件 只读//写进去
	FILE* ss = fopen("data.txt", "w");
	if (ss == NULL)
	{
		perror("fopen:w:"); 
		return 1;
	}
	fputs("hellow JJS", ss);
	fclose(ss);
	ss = NULL;


	//创建打开文件 只读
	FILE* ps = fopen("data.txt", "r");
	if (ps == NULL)
	{
		perror("fopen:w:");
		return 1;
	}
	//打开文件 创建文件 
	FILE* pf = fopen("data_copy.txt", "w");
	if (pf == NULL)
	{
		perror("fopen:w:");
		return 1;
	}


	//拷贝文件
	//一边读一边写,
	char ch = 0;
	//这里赋值给,ch 。ch 
	while ((ch = fgetc(ps)) != EOF)
	{
		fputc(ch, pf);
	}
	fclose(ps);
	fclose(pf);
	ps = NULL;
	pf = NULL;

	return 0;
}
//data 原始被拷贝文件
// 写文件 w把文件创建 =ss 负责接收
//读取创创建的文件  ps读取文件
//
//拷贝文件
//data_copy 拷贝文件到这个文件里面  
// pf 创建被拷贝的文件 首先创建 data_copy的文件 w的形式写进去
// 
// 
// 循环 把写入的data的字符 输入到data_copy里面  
// 首先是读取 也就是 fgetc 读取到eof之前都可循环
// 然后就是输入字符 也就是fputc函数 
// 循环输入 
// 这里是把 循环输出的函数 遍历 赋值给ch
// 此时 也就是fputc(ch,pf)
// 也就是把ch里面的遍历字符 输入到data_copy 也就是pf
//完成作业

举报

相关推荐

0 条评论