文件相关操作

2023-11-02

1.文件相关概念

1.1文件的概念

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

1.2流的概念

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

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

1.3 文本流

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

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

1.4 二进制流

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

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

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

比如说,在widows下,文件的换行符是\r\n,而在Linux下换行符则是\n.

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

2.文件操作

2.1. 文件流总览

标准库函数是的我们在C程序中执行与文件相关的I/O任务非常方便。下面是关于文件I/O的一般概况。

  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

2.2文件指针

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

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

 

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

struct _iobuf { 

        char  *_ptr;         //文件输入的下一个位置

        int   _cnt;          //剩余多少字符未被读取

        char  *_base;        //指基础位置(应该是文件的其始位置)

        int   _flag;         //文件标志

        int   _file;         //文件的有效性验证

        int   _charbuf;      //检查缓冲区状况,如果无缓冲区则不读取

        int   _bufsiz;       //文件的大小

        char  *_tmpfname;    //临时文件名

}; 

typedef struct _iobuf FILE;

3.文件打开关闭

 3.13文件打开(fopen)

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

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+”

以读/写方式打开一个二进制文件进行追加

示例代码:

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函数。它们将对这个指针执行间接访问,并将失败.

3.2文件关闭(fclose)

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

int fclose(FILE * stream);

功能:关闭先前fopen()打开的文件。此动作让缓冲区的数据写入文件中,并释放系统所提供的文件资源。

参数:

stream:文件指针

返回值:

成功:0

失败:-1

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

4.文件读写

  1. 按照字符读写文件:fgetc(), fputc()
  2. 按照行读写文件:fputs(), fgets()
  3. 按照块读写文件:fread(), fwirte()
  4. 按照格式化读写文件:fprintf(), fscanf()

字符读写函数回顾

int fputc(int ch, FILE * stream);

功能:将ch转换为unsigned char后写入stream指定的文件中

参数:

ch:需要写入文件的字符

stream:文件指针

返回值:

成功:成功写入文件的字符

失败:返回-1

int fgetc(FILE * stream);

功能:从stream指定的文件中读取一个字符

参数:

stream:文件指针

返回值:

成功:返回读取到的字符

失败:-1

int feof(FILE * stream);

功能:检测是否读取到了文件结尾

参数:

stream:文件指针

返回值:

非0值:已经到文件结尾

0:没有到文件结尾

示例代码:

void test(){

//写文件

FILE* fp_write= NULL;

//写方式打开文件

fp_write = fopen("./mydata.txt", "w+");

if (fp_write == NULL){

return;

}

char buf[] = "this is a test for pfutc!";

for (int i = 0; i < strlen(buf);i++){

fputc(buf[i], fp_write);

}

fclose(fp_write);

//读文件

FILE* fp_read = NULL;

fp_read = fopen("./mydata.txt", "r");

if (fp_read == NULL){

return;

}

#if 0

//判断文件结尾 注意:多输出一个空格

while (!feof(fp_read)){

printf("%c",fgetc(fp_read));

}

#else

char ch;

while ((ch = fgetc(fp_read)) != EOF){

printf("%c", ch);

}

#endif

}

将把流指针fp指向的文件中的一个字符读出,并赋给ch,当执行fgetc()函数时,若当时文件指针指到文件尾,即遇到文件结束标志EOF(其对应值为-1),该函数返回一个 -1 给ch,在程序中常用检查该函数返回值是否为 -1 来判断是否已读到文件尾,从而决定是否继续。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

文件相关操作 的相关文章

随机推荐