首页 >> 大全

C语言——文件操作(超全超详细)

2023-12-23 大全 32 作者:考证青年

C语言——文件操作 1. 什么是文件

磁盘上的文件是文件

但是在程序设计中,我们一般谈的文件有两种:程序文件、数据文件(从文件功能的角度来分类的)

1.1 程序文件

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

1.2 数据文件

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

而数据文件又分为文本文件和二进制文件

1.2.1 文本文件和二进制文件

数据在内存中以二进制的形式存储,如果不加转换的输出到外存,就是二进制文件

如果要求在外存上以ASCII码形式存储,则需要在存储前转换。以ASCII字符的形式存储的文件就是文本文件

例如对于整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占用5个字节(每个字符占一个字节),而二进制形式输出,则在磁盘上只占4个字节,如图所示

1.2.2 为什么要有文本文件

可能有小伙伴会问:文本文件只是二进制二进制文件的特殊形式,为什么要特殊照顾文本文件呢?

文本文件符合人类的阅读习惯、应用场景多,可以让人类简化操作保障数据读写的真实意图,这样能在不同的系统里有较好的兼容性可以有换行的概念‘\n’,字符有合法范围因此文件结束符可以特殊 1.3 文件名

一个文件对应一个唯一的文件标识(即文件名)

同一路径下不可能出现同名文件

文件名包含3部分:文件路径 + 文件名主干 + 文件后缀,例如:

注:文件名中不一定包含后缀名

文件路径又分为绝对路径和相对路径

1.3.4 绝对路径和相对路径

文件的绝对路径是指从根目录开始到文件的完整路径,包括所有的目录层级。例如,系统中的绝对路径可能是:“C:\Users\\\file.txt”

**相对路径是指相对于当前工作目录或者其他已知目录的路径。相对路径不包含根目录,而是使用特定的标识符来表示路径的位置关系。**例如,如果当前工作目录是"/home//",那么相对路径"file.txt"表示文件位于当前工作目录下的文件"file.txt"。

在相对路径中,还可以使用特殊的标识符来表示位置关系。例如,"…“表示父级目录,”."表示当前目录。因此,如果当前工作目录是"/home//",那么相对路径"…/file.txt"表示文件位于父级目录下的文件"file.txt"。

需要注意的是,相对路径是相对于当前工作目录或其他已知目录的路径,所以在不同的环境中可能会有不同的结果。因此,在编写代码或指定文件路径时,最好使用绝对路径来确保准确性和可移植性。

2. C语言中的流

什么是流?

在C语言中,“流”()是一种用于输入和输出数据的抽象概念。它是一种数据的传输方式,可以将数据从一个地方传送到另一个地方。在C语言中,输入流和输出流是通过一组标准库函数来实现的,这些函数允许程序从键盘或文件中读取数据,或者将数据写入到屏幕或文件中。

C语言中的流可以分为标准流( )和文件流(file )

注:C语言中操作流的主要函数是标准I/O库中的stdio.h头文件中定义的函数。

2.1 标准流

我们需要清楚,C语言程序,只要运行起来,就会默认打开3个流(标准流)

标准输入流(stdin):用于读取输入数据,默认情况下是键盘输入。

标准输出流():用于向终端或命令行窗口输出数据。

标准错误流():用于输出错误信息。

2.2 文件流

C语言中的文件流是一种用于在程序中读取和写入文件的流。通过文件流,可以在C程序中打开文件,从文件中读取数据或将数据写入文件中。这样可以有效地处理大量数据、持久性存储以及与文件系统的交互。

本次,我们重点讨论文件流

3. 文件指针

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

我们一般都是用过一个FILE的指针来维护这个FILE结构的变量,例如:

FILE* pf;	//文件指针变量

可以通过这个FILE指针pf来找到与这个文件对应的文件信息区

4. 文件的打开和关闭

在使用文件之前应该打开文件,使用完之后应该关闭文件

ANSIC规定用fopen来打开文件,用来关闭文件

FILE * fopen ( const char * filename, const char * mode );	//打开文件
int fclose ( FILE * stream );	//关闭文件

打开方式mode如下:

文件使用方式含义如果指定文件不存在

“r”(只读)

为了输入数据,打开一个已经存在的文本文件

出错

“w”(只写)

为了输出数据,打开一个文本文件(清空原有数据)

建立一个新的文件

“a”(追加)

向文本文件尾添加数据

建立一个新的文件

“rb”(只读)

为了输入数据,打开一个二进制文件

出错

“wb”(只写)

为了输出数据,打开一个二进制文件(清空原有数据)

建立一个新的文件

“ab”(追加)

向一个二进制文件尾添加数据

建立一个新的文件

“r+”(读写)

为了读和写,打开一个文本文件

出错

“w+”(读写)

为了读和写,创建一个新的文件(清空原有数据)

建立一个新的文件

“a+”(读写)

打开一个文件,在文件尾进行读写

建立一个新的文件

“rb+”(读写)

为了读和写打开一个二进制文件

出错

“wb+”(读写)

为了读和写新建一个二进制文件(清空原有数据)

建立一个新的文件

_c语言文件操作rb_c语言文件操作是什么意思

“ab+”(读写)

打开一个二进制文件,在文件尾进行读和写

建立一个新的文件

注1:当文件打开失败出错时,会返回一个空指针,因此我们一定要在打开文件之后,对文件指针进行有效性检查

注2:对于打开进行更新的文件(包含“+”号的文件),允许输入和输出操作,在写入操作之后的读取操作之前,应刷新()或重新定位流(fseek,,)。流应在读取操作之后的写入操作之前重新定位(fseek、、)(只要该操作未到达文件末尾)

例如:

#includeint main()
{//此时该路径下没有名为data.txt的文件,因此会打开失败FILE* fp = fopen("data.txt", "r");if (NULL == fp){perror("fopen");return 1;}fclose(fp);fp = NULL;return;
}

#includeint main()
{//用写的方式打开文件,如果文件不存在,会在该路径底下创建一个新的名为data.txt的文件FILE* fp = fopen("data.txt", "w");if (NULL == fp){perror("fopen");return 1;}fclose(fp);fp = NULL;return;
}

在上面我们使用的都是与执行文件相同路径底下的文件,如果是其他路径的文件又该如何打开呢?

有两种方法:

方法一:使用相对路径

例如我们要打开.18.c上一级目录中,文件夹Debug中的名为data.txt的文件:

#includeint main()
{FILE* fp = fopen("..\\Debug\\data.txt", "r");/*..表示Work_7.18.c文件的上一级目录Debug为该目录底下的文件夹*/if (NULL == fp){perror("fopen");return 1;}else{printf("SUCCESS\n");}fclose(fp);fp = NULL;return;
}

方法二:绝对路径

例如,我们要打开桌面上的名为data.txt的文件

#includeint main()
{FILE* fp = fopen("C:\\Users\\HUASHUO\\Desktop\\data.txt", "r");if (NULL == fp){perror("fopen");return 1;}else{printf("SUCCESS\n");}fclose(fp);fp = NULL;return;
}

注:本来,文件地址为"C:\Users\\\data.txt",但为了和转义字符做区分,应该在每一个反斜杠后面再加一个反斜杠:“C:\\Users\\\\\\data.txt”

5. 文件输入和文件输出的概念

可能有许多小伙伴会认为,文件的输入就是将数据写到文件里,文件的输出就是将文件的内容读取出来,然而事实却恰恰相反

文件输入(File Input): 文件输入是指将外部文件中的数据读取到程序中进行处理的过程。

文件输出(File ):是指将程序中的数据写入到外部文件中的过程。

我们也可以画一个图来表示这个关系:

6. 文件的顺序读写 6.1 顺序读写的函数 功能函数名适用于

字符输入函数

fgetc

所有输入流

字符输出函数

fputc

所有输出流

文本输入函数

fgets

所有输入流

文本输出函数

fputs

所有输出流

格式化输入函数

所有输入流

格式化输出函数

所有输出流

二进制输入

fread

文件

二进制输出

文件

6.1.1 fgetc

int fgetc ( FILE * stream );

示例:

若在.c文件的路径下有一名为data.txt的文件,这个文件有字符串“”

#includeint main()
{FILE* fp = fopen("data.txt", "r");if (NULL == fp){perror("fopen");return 1;}char ch;while ((ch = fgetc(fp)) != EOF)printf("%c", ch);printf("\n");fclose(fp);fp = NULL;return;
}

:

abcdef

6.1.2 fputc

int fputc ( int character, FILE * stream );

示例:

向同一文件逐个写入26个小写英文字符

#includeint main()
{FILE* fp = fopen("data.txt", "w");if (NULL == fp){perror("fopen");return 1;}char ch = 'a';char ret;for (int i = 0; i < 26; i++){ret = fputc(ch + i, fp);printf("%c", ret);}fclose(fp);fp = NULL;return;
}

:

abcdefghijklmnopqrstuvwxyz

6.1.3 fgets

char * fgets ( char * str, int num, FILE * stream );

示例1:

从文件中读取26个小写字母

#includeint main()
{FILE* fp = fopen("data.txt", "r");if (NULL == fp){perror("fopen");return 1;}char ch[30] = {0};fgets(ch, 26 + 1, fp);puts(ch);fclose(fp);fp = NULL;return;
}

:

abcdefghijklmnopqrstuvwxyz

示例2:

从文件读取以下内容:

123
456

:

123

6.1.3.1 fgets和gets的区别

fgets:

char * fgets ( char * str, int num, FILE * stream );

gets:

char * gets ( char * str );

例如:

#includeint main()
{char str1[20] = { 0 };char str2[20] = { 0 };gets(str1);fgets(str2, 5 + 1, stdin);return 0;
}

同时在标准输入流读入“abcd\n”,利用调试,可以发现二者区别

6.1.4 fputs

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

例如:

将字符串“”写入文件

#includeint main()
{FILE* fp = fopen("data.txt", "w");if (NULL == fp){perror("fopen");return 1;}char ch[] = "abcdef";int ret = fputs(ch, fp);printf("%d", ret);fclose(fp);fp = NULL;return;
}

0

6.1.4.1 fputs和puts的区别

fputs:

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

puts:

int puts ( const char * str );

例如:

#includeint main()
{char str[] = "abcdef";puts(str);printf("HELLO");printf("\n");fputs(str, stdout);printf("HELLO");printf("\n");return 0;
}

abcdef
HELLO
abcdefHELLO

6.1.5

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

例如:

从文件中读取数字123和字符串“”

#includeint main()
{FILE* fp = fopen("data.txt", "r");if (NULL == fp){perror("fopen");return 1;}char str[10] = { 0 };int num = 0;fscanf(fp, "%d %s", &num, str);printf("%d\n%s\n", num,str);fclose(fp);fp = NULL;return;
}

:

123
abcdef

6.1.5.1 scanf//

scanf:

int scanf ( const char * format, ... );

:

int sscanf ( const char * s, const char * format, ...);

:

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

例如:

文件内容为: 123

#includeint main()
{FILE* fp = fopen("data.txt", "r");if (NULL == fp){perror("fopen");return 1;}int num1 = 0;int num2 = 0;int num3 = 0;char str1[20] = "123 abcdef";char str2[10] = { 0 };char str3[10] = { 0 };scanf("%d", &num1);sscanf(str1, "%d%s", &num2, str2);fscanf(fp, "%d%s", &num3, str3);printf("num1 = %d, str1 = %s\n", num1, str1);printf("num2 = %d, str2 = %s\n", num2, str2);printf("num3 = %d, str3 = %s\n", num3, str3);fclose(fp);fp = NULL;return 0;
}

input:

123

:

num1 = 123, str1 = 123 abcdef
num2 = 123, str2 = abcdef
num3 = 123, str3 = abcdef

6.1.6

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

例如:

将数字123和字符串“”写入文件

#includeint main()
{FILE* fp = fopen("data.txt", "w");if (NULL == fp){perror("fopen");return 1;}char str[10] = "abcdef";int num = 123;int ret = fprintf(fp, "%d%s", num, str);printf("ret = %d\n", ret);fclose(fp);fp = NULL;return;
}

:

ret = 9

注:如果在%d%f中加入一个空格,那么返回值就会加一

6.1.6.1 //

:

int printf ( const char * format, ... );

:

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

:

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

例如:

#includeint main()
{FILE* fp = fopen("data.txt", "w");if (NULL == fp){perror("fopen");return 1;}int num1 = 10;int num2 = 10;int num3 = 0;char str1[10] = "abcdef";char str2[10] = { 0 };printf("num1 = %d\n", num1);sprintf(str2, "%s", str1);puts(str2);fprintf(fp, "%d %s", num1, str1);fclose(fp);fp = NULL;return 0;
}

:

num1 = 10
abcdef

6.1.7 fread

size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );

例如:

读取文件中的字符串“1200”

int main()
{FILE* fp = fopen("data.txt", "rb");if (NULL == fp){perror("fopen");return 1;}int str[10] = {0};int ret = fread(str, sizeof(int), 1, fp);for (int i = 0; i < 10; i++)printf("%d ", str[i]);printf("\nret = %d\n", ret);fclose(fp);fp = NULL;return;
}

:

808464945 0 0 0 0 0 0 0 0 0
ret = 1

注:

对小端字节序存储该不太了解的同学请看这里传送门

在C语言中,文件的数据存储方式取决于计算机的体系结构和操作系统。通常情况下,对于大多数计算机系统,文件的数据是按照字节顺序存储的,这意味着在内存中,文件前面的数据存储在较低的地址,后面的数据存储在较高的地址。

6.1.8

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

例如:

向文件中写入字符串“”

#includeint main()
{FILE* fp = fopen("data.txt", "wb");if (NULL == fp){perror("fopen");return 1;}char str[] = "abcdef";int ret = fwrite(str, sizeof(char), strlen(str), fp);printf("%d\n", ret);fclose(fp);fp = NULL;return 0;
}

:

6

7. 文件的随机读写

注1:当文件被打开时,文件指针默认值向文件的起始位置

注2:当文件以追加的方式打开时,不允许人为改变文件指针位置

7.1 fseek

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

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

:文件头

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了