云计算百科
云计算领域专业知识百科平台

文件操作详解

一、什么是文件?

1.文件的基本概念

文件是存储在计算机或其他数字设备中的信息集合,通常以特定格式组织,用于保存数据、程序或文档。文件通过文件名和扩展名标识,例如 report.docx(文档文件)或 data.xlsx(电子表格文件)。要是没有文件,我们写的程序的数据是存储在电脑的内存中,如果程序退出,内存回收,数据就丢失了,等再次运行程序,就看不到上次程序的数据。

2.文件的常见类型

·文本文件(如 .txt、.csv):存储纯文本或结构化数据。

·文档文件(如 .docx、.pdf):包含格式化文本、图像等,通常由办公软件创建。

·媒体文件(如 .mp3、.mp4):存储音频、视频或图像数据。

·可执行文件(如 .exe、.app):包含程序指令,可直接运行。

在程序设计中,我们可以把上面的文件类型大致分为两类:程序文件、数据文件(从文件功能的角度来分类 的)。

2.1程序文件

程序文件包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows 环境后缀为.exe)。

2.2数据文件

文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,或者输出内容的文件。

本章的重点就是数据文件!

3.文件的组成要素

  • 文件名:文件的唯一标识符,通常由用户自定义(如 project_plan)。
  • 扩展名:后缀(如 .txt、.jpg),用于指示文件类型和关联的应用程序。
  • 内容:文件内部存储的实际数据,可以是文本、图像、音频、代码等。

4.文件的管理

  • 存储位置:文件保存在硬盘、U盘、云存储等介质中,通过目录(文件夹)分类管理。
  • 操作:包括创建、打开、编辑、复制、移动、删除等,可通过操作系统或应用程序完成。

5.二进制文件和文本文件

根据数据的组织形式,数据文件被称为文本文件或者二进制文件。

数据在内存中以二进制的形式存储,如果不加转换的输出到外存的文件中,就是二进制文件。 如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的文件就是文本文件。

一个数据在文件中是怎么存储的呢? 字符一律以ASCII形式存储,数值型数据既可以用ASCII形式存储,也可以使用二进制形式存储。 如有整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占用5个字节(每个字符一个字节),而二进制形式输出,则在磁盘上只占4个字节。

两类文件的存储形式如下图所示:

6.文件的打开与关闭

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

6.1 文件指针

文件指针是C语言中用于操作文件的重要工具,它是一个指向上述文件结构体的指针,用于跟踪文件当前读写位置。文件指针的类型为FILE*,通常与文件操作函数如fopen、fclose、fread、fwrite等配合使用。

6.2文件指针的声明与初始化

FILE* pf1;

定义pf1是一个指向FILE类型数据的指针变量。可以使pf指向某个文件的文件信息区(是一个结构体变量)。通过该文件信息区中的信息就能够访问该文件。也就是说,通过文件指针变量能够间接找到与它关联的文件。用图来表达的话就是:

初始化时就可以调用文件操作函数如fopen,如下:

FILE *fp;
fp = fopen("example.txt", "r"); // 以只读模式打开文件
if (fp == NULL) {
perror("Error opening file");
return 1;
}

6.3 文件的打开与关闭

如果我们想要进行读写文件的操作,就要先把文件打开,读写完成后就要把文件关闭。

那要如何操作呢?

规定上,我们可以使用fopen来打开文件,fclose来关闭文件。

1.)fopen

第一个参数表示文件名

第二个参数mode表示文件的打开模式

以下是文件打开模式的综合:

文件打开模式表格

模式描述文件存在时文件不存在时
r 只读模式 打开文件 报错 (FileNotFoundError)
w 写入模式 清空文件内容 创建新文件
a 追加模式 在文件末尾追加内容 创建新文件
r+ 读写模式 打开文件,可读写 报错 (FileNotFoundError)
w+ 读写模式 清空文件内容,可读写 创建新文件
a+ 读写模式 在文件末尾追加内容,可读写 创建新文件
x 独占创建模式 报错 (FileExistsError) 创建新文件

二进制文件模式

在模式后加 b 表示以二进制方式操作文件(如 rb, wb, ab 等)。例如:

  • rb:二进制只读模式
  • wb:二进制写入模式
  • ab:二进制追加模式

其他加b的情况都是二进制文件的操作模式,以下略。

2.)fclose

fclose比较简单,一个参数就是指向要关闭的文件的指针。

7.文件的顺序读写

7.1文件的顺序读写函数:

函数名功能描述示例代码片段
fopen() 打开文件 FILE *fp = fopen("file.txt", "r");
fclose() 关闭文件 fclose(fp);
fgetc() 读取单个字符 char ch = fgetc(fp);
fputc() 写入单个字符 fputc('A', fp);
fgets() 读取字符串(行) fgets(buffer, 100, fp);
fputs() 写入字符串 fputs("Hello", fp);
fscanf() 格式化读取 fscanf(fp, "%d", &num);
fprintf() 格式化写入 fprintf(fp, "Value: %d", num);
feof() 检测文件结束 while(!feof(fp)){…}
rewind() 重置文件指针到开头 rewind(fp);

7.2 根据上面的函数以及文件的打开模式,有下列的实例可供参考:

在上述代码我们可以看到,它通过fopen函数用‘w’写入模式打开目标文件,然后使用fputs函数将一串字符写入到了我们的myfile.txt文件中。

然后,我们更改打开模式为‘r'只读模式,通过fgets函数将myfile.txt文件中的字符串读取到字符串数组arr中,并将其打印。

7.3 各种scanf、printf的对比

1.)SCANF

1.1)fcanf

fscanf 是 C 语言中用于从文件中读取格式化输入的函数,类似于 scanf,但操作对象是文件流而非标准输入。函数原型如下:

int fscanf(FILE *stream, const char *format, …);

参数:

  • stream:指向文件流的指针(通过 fopen 打开)。
  • format:格式化字符串,指定输入数据的解析方式。
  • …:可变参数,用于存储读取的数据(需为变量地址)。

基本用法如下:

1.2)sscanf

sscanf 是 C 标准库中的一个函数,用于从字符串中按照指定格式读取数据。其功能类似于 scanf,但输入源是字符串而非标准输入。函数原型如下:

int sscanf(const char *str, const char *format, …);

  • str:待解析的输入字符串。
  • format:格式控制字符串,指定如何解析输入。
  • …:可变参数,用于存储解析结果。

以下是基本用法:

#include <stdio.h>

int main() {
const char *str = "42 3.14";
int num;
float pi;

int result = sscanf(str, "%d %f", &num, &pi);
printf("Parsed %d values: %d, %.2f\\n", result, num, pi);
return 0;
}

2.)PRINTF

2.1)fprintf

fprintf 是 C 语言标准库中的一个函数,用于将格式化输出写入文件流。其功能类似于 printf,但 printf 默认输出到标准输出(通常是屏幕),而 fprintf 可以指定输出到任意文件流(如文件、标准错误等)。函数原型如下:

int fprintf(FILE *stream, const char *format, …);

参数:

  • stream:指向文件流的指针,可以是 stdout、stderr 或通过 fopen 打开的文件。
  • format:格式字符串,指定输出的格式。
  • …:可变参数,根据格式字符串的要求提供相应的变量。

基本用法如下:

2.2)sprintf

sprintf 是一个在多种编程语言中用于格式化字符串的函数, printf 函数用于将格式化字符串输出到标准输出(如屏幕),而 sprintf 则是将格式化字符串写入一个字符数组(字符串)中,而不是直接输出。它返回写入的字符数(不包括结尾的空字符)。函数原型如下:

int sprintf(char *str, const char *format, …);

参数:

  • str:目标字符数组,用于存储格式化后的字符串。
  • format:格式化字符串,包含普通字符和格式说明符(如 %d、%f)。
  • …:可变参数,根据 format 中的格式说明符填入。

基本用法如下:

#include <stdio.h>
int main() {
char buffer[50];
int num = 123;
float pi = 3.14;

// 格式化整数和浮点数
sprintf(buffer, "Number: %d, Pi: %.2f", num, pi);
printf("%s\\n", buffer); // 输出: "Number: 123, Pi: 3.14"

return 0;
}

8.文件的随机读写

有顺序读写,就要有随机读写。随机读写让我们对文件的输入输出有了更灵活的方式。

8.1 fseek

根据文件指针的位置和偏移量来定位文件指针。

int fseek ( FILE * stream, long int offset, int origin );

1.)fseek的第三个参数

fseek函数的第三个参数用于指定偏移量的参考位置,即从文件的哪个位置开始计算偏移量。该参数通常是一个预定义的常量,具体如下:

SEEK_SET
表示从文件开头开始计算偏移量。例如,fseek(fp, 10, SEEK_SET)将文件指针移动到距离文件开头10字节的位置。

SEEK_CUR
表示从当前文件指针位置开始计算偏移量。例如,fseek(fp, 5, SEEK_CUR)将文件指针从当前位置向后移动5字节。

SEEK_END
表示从文件末尾开始计算偏移量。例如,fseek(fp, -3, SEEK_END)将文件指针移动到距离文件末尾3字节的位置。

2.)使用案例:

int main()
{
FILE* pFile;
pFile = fopen("myfile.txt", "w");
if (pFile == NULL)
{
perror("fopen");
return 1;
}
fputs("This is an apple.", pFile);
fseek(pFile, 9, SEEK_SET);
fputs(" sam", pFile);
fclose(pFile);
return 0;
}

最后的结果就是:

我们可以看到fseek函数将指针的位置放到了原字符串的第九位,然后进行修改,就变成了“This is a sample".

8.2 ftell

返回文件指针相对于起始位置的偏移量

long int ftell ( FILE * stream );

我们可以将ftell函数与fseek函数搭配使用,举例如下:

#include<stdio.h>
int main()
{
FILE* pFile;
long size;
pFile = fopen("myfile.txt", "rb");
if (pFile == NULL)
perror("Error opening file");
else
{
fseek(pFile, 0, SEEK_END);
size = ftell(pFile);
fclose(pFile);
printf("Size of myfile.txt: %ld bytes.\\n", size);
}
return 0;
}

8.3 rewind

rewind函数用于将文件指针重置到文件的开头位置,同时清除文件流的错误标志。它常用于需要重复读取文件内容的场景,无需关闭再重新打开文件。

void rewind(FILE *stream);

典型用法如下:

FILE *file = fopen("example.txt", "r");
if (file == NULL) {
perror("文件打开失败");
return 1;
}

// 第一次读取文件内容
char buffer[100];
fgets(buffer, sizeof(buffer), file);
printf("第一次读取: %s", buffer);

// 重置文件指针到开头
rewind(file);

// 第二次读取相同内容
fgets(buffer, sizeof(buffer), file);
printf("第二次读取: %s", buffer);

fclose(file);

9. 文件读取结束判定

1.feof 的作用

当文件读取结束的时候,判断是读取结束的原因是否是:遇到文件尾结束。因此,我们不能直接使用feof 来判定文件是否读取结束。所以我们还要使用其他办法来判定。

2. 文本文件读取是否结束,判断返回值是否为EOF (fgetc),或NULL(fgets)。

例:

#include <stdio.h>
#include <stdlib.h>
int main()
{
int c; // 注意:int,⾮char,要求处理EOF
FILE* fp = fopen("test.txt", "r");
if(fp==NULL)
{
perror("File opening failed");
return 1;
}
//fgetc 当读取失败的时候或者遇到⽂件结束的时候,都会返回EOF
while ((c = fgetc(fp)) != EOF)
{
putchar(c);
}
//判断是什么原因结束的
if (ferror(fp))
puts("I/O error when reading");
else if (feof(fp))
puts("End of file reached successfully");
fclose(fp);
}

10. 文件缓冲区

       ANSIC标准采用“缓冲文件系统”处理的数据文件的,所谓缓冲文件系统是指系统自动地在内存中为 程序中每一个正在使用的文件开辟一块“文件缓冲区”。从内存向磁盘输出数据会先送到内存中的缓 冲区,装满缓冲区后才一起送到磁盘上。如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓冲区的大小根据C编译系统决定的。功能大致如下图所示:

10.1 注意事项

  • 程序正常终止或文件关闭时,缓冲区内容会自动刷新。
  • 缓冲区未刷新时程序异常退出可能导致数据丢失。
  • 默认缓冲模式因系统和文件类型而异。

赞(0)
未经允许不得转载:网硕互联帮助中心 » 文件操作详解
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!