文件操作pro

警告
本文最后更新于 2023-12-31,文中内容可能已过时。

​ 一个文件通常就是磁盘上一段命名的存储区。但是对于操作系统来说,文件就会更复杂一些。例如,一个大文件可以存储在一些分散的区段中,或者还会包含一些操作系统可以确定其文件类型的附加数据,但是这些是操作系统,而不是我们程序员所要关心的事情。我们应该考虑如何在C程序中处理文件。

​ 流是一个动态的概念,可以将一个字节形象地比喻成一滴水,字节在设备、文件和程序之间的传输就是流,类似于水在管道中的传输,可以看出,流是对输入输出源的一种抽象,也是对传输信息的一种抽象。

​ C语言中,I/O操作可以简单地看作是从程序移进或移出字节,这种搬运的过程便称为流(stream)。程序只需要关心是否正确地输出了字节数据,以及是否正确地输入了要读取字节数据,特定I/O设备的细节对程序员是隐藏的。

​ 文本流,也就是以文本模式读取文件。文本流的某些特性在不同的系统中不同。其中之一就是文本行的最大长度。标准规定至少允许254个字符。另一个可能不同的特性是文本行的结束方式。例如在Windows系统中,文本文件约定以一个回车符和一个换行符结尾。但是在Linux下只用一个换行符结尾

​ 标准的C把文件定义为零个或多个字符,后面跟一个表示结束的换行符\n。对于那些文本行的外在表现形式与这个定义不同的系统上,库函数负责外部形式与内部形式之间的翻译。例如,在Windows系统中,在输出时,文本的换行符被写成一对回车/换行符。在输入时,文本中的回车符被丢弃。这种不必考虑文本的外部形式而操作文本的外部形式而操作文本的能力简化了可移值程序的创建。

​ 二进制流中的字节将完全根据程序编写他们的形式写入到文件中,而且完全根据他们从文件或设备读取的形式度入到从程序中。他们并未作任何改变。这种类型的流适用于非文本数据,到那时如果你不希望I/O函数修改文本文件的行末字符,也可以把他们运用于文本文件。

​ c语言在处理这两种文件的时候并不区分,都看成是字符流,按字节进行处理。

​ 我们程序中,经常看到文本方式打开文件的二进制方式打开文件仅仅体现在换行符的处理上。

​ 比如说,在Windows下,文件的换行符是\r\n,而在Linux下换行符是\n

​ 当对文件使用文本方式打开时,读写的Windows文件中的换行符\r\n会被替换成\n读到内存中,当在Windows下写入文件时,\n会被替换成\r\n再写入文件。如果使用二进制的方式打开文件,则不进行\r\n和\n之间的转换,那么由于Linux下的换行符就是\n,所以文本文件方式和二进制方式无区别。

  1. 程序为通吃处于活动状态的每个文件声明一个指针变量,其类型为FILE*。这个指针指向这个FILE结构,当他处于活动状态时由流使用。
  2. 流通过fopen函数打开。为了打开一个流,我们必须指定需要访问的文件或设备以及他们的访问方式(读。写、或者读写)。fopen和操作系统验证文件或设备是否存在并初始化FILE。
  3. 根据需要对文件进行读写操作。
  4. 最后调用fclose函数关闭流。关闭一个流可以防止与它相关的文件被再次访问,保证任何存储于缓冲区中的数据被正确写入到文件中,并且释放file结构。

标准I/O更为简单,因为它们并不需要打开或者关闭。

I/O函数以三种基本的形式处理数据:单个字符文本行二进制数据。对于每种形式都有一组特定的函数对它们进行处理。

家族名 目的 可用于所有流 只用于stdin和stdout
getchar 字符输入 fgetc、getc getchar
putchar 字符输出 fputc、putc putchar
gets 文本行输入 fgets gets
puts 文本行输出 fputs puts
scanf 格式化输入 fscanf scanf
printf 格式化输出 fprintf printf

​ 我们知道,文件是由操作系统管理的单元。当我们想操作一个文件的时候,让操作系统帮我们打开文件,操作系统把我们指定要打开文件的信息保存起来,并且返回给我们一个指针指向文件的信息。文件指针也可以理解为代指打开的文件。这个指针的类型为FILE类型。该类型定义在stdio.h头文件中。通过文件指针,我们就可以对文件进行各种操作。

​ 对于每一个ANSI C程序,运行时系统必须提供至少三个流-标准输入(stdin)、标准输出(stdout)、标准错误(stderr),它们都是一个指向FILE结构的指针。标准输入是缺省情况下的输入来源,标准输出时缺省情况下的输出设置。具体缺省值因编译器而异,通常标准输入为键盘设备、标准输出为终端或者屏幕。

img

ANSI C并未规定FILE的成员,不同编译器可能有不同的定义。VS下FILE信息如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
struct _iobuf { 
        char  *_ptr;         //文件输入的下一个位置 
        int   _cnt;          //剩余多少字符未被读取
        char  *_base;        //指基础位置(应该是文件的其始位置) 
        int   _flag;         //文件标志 
        int   _file;         //文件的有效性验证 
        int   _charbuf;      //检查缓冲区状况,如果无缓冲区则不读取 
        int   _bufsiz;       //文件的大小 
        char  *_tmpfname;    //临时文件名 
}; 
typedef struct _iobuf FILE;

文件缓冲区

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

那么文件缓冲区有什么作用呢?

​ 如我们从磁盘里取信息,我们先把读出的数据放在缓冲区,计算机再直接从缓冲区中取数据,等缓冲区的数据取完后再去磁盘中读取,这样就可以减少磁盘的读写次数,再加上计算机对缓冲区的操作大大快于对磁盘的操作,故应用缓冲区可大大提高计算机的运行速度。

img

​ 文件的打开操作表示将给用户指定的文件在内存分配一个FILE结构区,并将该结构的指针返回给用户程序,以后用户程序就可用此FILE指针来实现对指定文件的存取操作了。当使用打开函数时,必须给出文件名、文件操作方式(读、写或读写)。

1
2
3
4
5
6
7
8
FILE * fopen(const char * filename, const char * mode);
功能:打开文件
参数:
	filename:需要打开的文件名,根据需要加上路径
	mode:打开文件的权限设置
返回值:
	成功:文件指针
	失败:NULL
方式 含义
“r” 打开,只读,文件必须已经存在。
“w” 只写,如果文件不存在则创建,如果文件已存在则把文件长度截断(Truncate)为0字节。再重新写,也就是替换掉原来的文件内容文件指针指到头。
“a” 只能在文件末尾追加数据,如果文件不存在则创建
“rb” 打开一个二进制文件,只读
“wb” 打开一个二进制文件,只写
“ab" 打开一个二进制文件,追加
“r+” 允许读和写,文件必须已存在
“w+” 允许读和写,如果文件不存在则创建,如果文件已存在则把文件长度截断为0字节再重新写 。
“a+” 允许读和追加数据,如果文件不存在则创建
“rb+” 以读/写方式打开一个二进制文件
“wb+” 以读/写方式建立一个新的二进制文件
“ab+” 以读/写方式打开一个二进制文件进行追加
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
void test(){
	
	FILE *fp = NULL;

	// "\\"这样的路径形式,只能在windows使用
	// "/"这样的路径形式,windows和linux平台下都可用,建议使用这种
	// 路径可以是相对路径,也可是绝对路径
	fp = fopen("../test", "w");
	//fp = fopen("..\\test", "w");

	if (fp == NULL) //返回空,说明打开失败
	{
		//perror()是标准出错打印函数,能打印调用库函数出错原因
		perror("open");
		return -1;
	}
}

应该检查fopen的返回值!如何函数失败,它会返回一个NULL值。如果程序不检查错误,这个NULL指针就会传给后续的I/O函数。它们将对这个指针执行间接访问,并将失败.

​ 文件操作完成后,如果程序没有结束,必须要用fclose()函数进行关闭,这是因为对打开的文件进行写入时,若文件缓冲区的空间未被写入的内容填满,这些内容不会写到打开的文件中。只有对打开的文件进行关闭操作时,停留在文件缓冲区的内容才能写到该文件中去,从而使文件完整。再者一旦关闭了文件,该文件对应的FILE结构将被释放,从而使关闭的文件得到保护,因为这时对该文件的存取操作将不会进行。文件的关闭也意味着释放了该文件的缓冲区。

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

​ 它表示该函数将关闭FILE指针对应的文件,并返回一个整数值。若成功地关闭了文件,则返回一个0值,否则返回一个非0值.

  • 按照字符读写文件:fgetc(), fputc()
  • 按照行读写文件:fputs(), fgets()
  • 按照块读写文件:fread(), fwirte()
  • 按照格式化读写文件:fprintf(), fscanf()
  • 按照随机位置读写文件:fseek(), ftell(), rewind()

相关内容