文件操作(C语言)

简介: 文件操作(C语言)

1. 文件定义

文件分为程序文件和数据文件。本文讨论的是数据文件。

1.1 程序文件

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

1.2 数据文件

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

1.3 文件名

一个文件要有唯一的文件标识,以便用户进行识别。文件名包含三部分:文件路径+文件名主干+文件后缀。

例如:C:\code\text.txt 为了方便起见,文件标示被称为i文件名。

2.文件操作

为了能够将我们输入的数据永久的存储起来,C语言提供了一系列的库函数,帮助我们来完成数据的永久存储与读取工作。

2.1 文件指针

顾名思义:指向文件的指针。

指针类型为FILE

FILE * pf;

当我们想要打开文件时,OS会根据我们提供的文件标识,去硬盘里将文件部分信息加载到内存中,并且声明一个FILE类型的文件信息区,存取当前文件的各种信息。并且会返回给用户一个指向该文件信息区的指针pf,用户通过pf对文件进行各种操作。

如图:每个指针变量都指向各自的文件。

2.2 文件打开和关闭

和动态内存开辟相似,用户在对文件进行操作时,首先要打开文件,结束操作后,要将文件关闭。

//打开文件

FILE * fopen ( const char * filename, const char * mode );

//关闭文件

int fclose ( FILE * stream );

打开方式如下:

文件使用方式 含义 如果指定文件不存在
“r”(只读) 为了输入数据,打开一个已经存在的文本文件 出错
“w”(只写) 为了输出数据,打开一个文本文件 建立一个新的文件
“a”(追加) 向文本文件尾添加数据 建立一个新的文件
“rb”(只读) 为了输入数据,打开一个二进制文件 出错
“wb”(只写) 为了输出数据,打开一个二进制文件 建立一个新的文件
“ab”(追加) 向一个二进制文件尾添加数据 出错
“r+”(读写) 为了读和写,打开一个文本文件 出错
“w+”(读写) 为了读和写,建立一个新的文件 建立一个新的文件
“a+”(读写) 打开一个文件,在文件尾进行读写 建立一个新的文件
“rb+”(读写) 为了读和写打开一个二进制文件 出错
“wb+”(读写) 为了读和写,新建一个新的二进制文件 建立一个新的文件
“ab+”(读写) 打开一个二进制文件,在文件尾进行读和写 建立一个新的文件

文件打开示例:用只读的方式打开一个不存在的文件(注意要用\\进行转义

以"w"的方式打开,如果文件不存在会创建一个text.txt文件。

3. 文件顺序读写

打开文件后我们就可以对文件进行操作,下面介绍顺序读写的一些函数。

功能 函数名 适用于
字符输入函数 fgetc 所有输入流
字符输出函数 fputc 所有输出流
文本行输入函数 fgets 所有输入流
文本行输出函数 fputs 所有输出流
格式化输入函数 fscanf 所有输入流
格式化输出函数 fprintf 所有输出流
二进制输入 fread 文件
二进制输出 fwrite 文件

3.1 输入输出函数对比

流:为了便于简化操作,封装出流的概念,流是一个高度的抽象,表示着数据流动。有了这个概念后,我们就可以统一的对各种设备进行IO,而防止差异性。

3.1.1 fgetc和fputc

int fgetc( FILE *stream );

从流中读一个字符,函数返回读到的字符。返回EOF代表输入错误或者读到文件末尾。

int fputc( int c, FILE *stream );

写一个字符到流中,返回EOF代表输出错误。

示例1:在键盘上输入,在屏幕上输出

示例2:将a~z写入文件中。

示例3:将文件中的信息读出来,输出到屏幕上。

3.1.2 fgets和fputs

char *fgets( char *string, int n, FILE *stream );

从流中读取n个数据到字符指针中,返回值为NULL,意味着文件结束,或者错误。

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

把字符串的内容输出到流中。

示例1:向文件中写入两个字符串

示例2:从文件中读取一个字符串(读取n-1个),要留一个位置给‘\0’,读到\n就停止了

3.1.3 scanf和printf

格式化的输入输出函数

int scanf( const char *format [,argument]… );

int printf( const char *format [, argument]… );

比较熟悉,不再讲解。

3.1.4 fscanf 和fprintf

针对所有输入流的格式化输入函数

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

针对所有输出流的格式化输出函数

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

用法和scanf和printf极其类似。

示例1:将结构体数据输出到文件中。

示例2:将数据从文件读到结构体中。

3.1.5 sscanf和sprintf

把一个字符串转化成格式化的数据

int sscanf( const char *buffer, const char *format [, argument ] … );

把一个格式化的数据转化成字符串

int sprintf( char *buffer, const char *format [, argument] … );

下面是使用示例:

3.1.6 fread和fwrite

从buf中写count个大小为size的数据到流中。返回值为写入的数量。

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

从流中读取count个大小为size的数据到buf,返回值为读出的数量

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

示例1:将数据写入文件中

示例2:将文件中的数据读出来。

4. 文件随机读写

4.1 fseek

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

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

origin有三种格式:SEEK_CUR当前位置 SEEK_END末尾位置 SEEK_SET开始位置。

示例:调整pf的指针位置

4.2 ftell

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

long int ftell ( FILE * stream );

示例:读取了两个字符,偏移量应为2。

4.3 rewind

让文件指针的位置回到文件的起始位置

void rewind ( FILE * stream );

示例:让文件指针回到起始位置

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

根据数据的组织形式,数据被分为文本文件和二进制文件。数据在内存中以二进制的方式进行存储,如果不加以转换存储到外存,就是二进制文件。如果在存储前转化成ASCII码的形式,就是文本文件。

其中:字符一律以ASCII码形式存储,数值型数据既可以以ASCII码形式存储,也可以用二进制形式存储。

示例:

6. 文件读取结束的判定

在判断文件是否读取结束时,不能单单判断文件是否读取到末尾结束,还应该判断文件是否读取出错而结束。

  1. 文本文件是否读取结束判断返回值是否为 EOF ( fgetc ),或者 NULL ( fgets )
  2. 二进制文件的读取结束判断,判断返回值是否小于实际要读的个数(fread)。

文本文件示例:

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

要先用ferror判断文件是否错误结束,在判断是否读到末尾正常结束。

二进制文件示例:

#include <stdio.h>
enum { SIZE = 5 };
int main(void)
{
    double a[SIZE] = {1.,2.,3.,4.,5.};
    FILE *fp = fopen("test.bin", "wb"); // 必须用二进制模式
    fwrite(a, sizeof *a, SIZE, fp); // 写 double 的数组
    fclose(fp);
    double b[SIZE];
    fp = fopen("test.bin","rb");
    size_t ret_code = fread(b, sizeof *b, SIZE, fp); // 读 double 的数组
    if(ret_code == SIZE) {
        puts("Array read successfully, contents: ");
        for(int n = 0; n < SIZE; ++n) printf("%f ", b[n]);
        putchar('\n');
   } else { // error handling
       if (feof(fp))
          printf("Error reading test.bin: unexpected end of file\n");
       else if (ferror(fp)) {
           perror("Error reading test.bin");
       }
   }
    fclose(fp);
}

同样需要判断文件是否正常结束或是异常结束

7. 文件缓冲区

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

通俗来讲文件写入磁盘时,要先写入输出缓冲区,然后再写入磁盘;读入数据时,先从磁盘读到输入缓冲区,再读到内存中。

简单证明示例:

#include <stdio.h>
#include <windows.h>
//VS2013 WIN10环境测试
int main()
{
 FILE*pf = fopen("test.txt", "w");
 fputs("abcdef", pf);//先将代码放在输出缓冲区
 printf("睡眠10秒-已经写数据了,打开test.txt文件,发现文件没有内容\n");
 Sleep(10000);
 printf("刷新缓冲区\n");
 fflush(pf);//刷新缓冲区时,才将输出缓冲区的数据写到文件(磁盘)
 //注:fflush 在高版本的VS上不能使用了
 printf("再睡眠10秒-此时,再次打开test.txt文件,文件有内容了\n");
 Sleep(10000);
 fclose(pf);
 //注:fclose在关闭文件的时候,也会刷新缓冲区
 pf = NULL;
 return 0;
}

结论:因为有缓冲区的存在,C语言在操作文件的时候,需要做刷新缓冲区或者在文件操作结束的时候关闭文

件。

如果不做,可能导致读写文件的问题

以上是文件相关知识介绍,后续还会继续更新,如有问题,恳请大佬指点💖

目录
相关文章
|
28天前
|
存储 C语言
【c语言】玩转文件操作
本文介绍了C语言中文件操作的基础知识,包括文件的打开和关闭、文件的顺序读写、文件的随机读写以及文件读取结束的判定。详细讲解了`fopen`、`fclose`、`fseek`、`ftell`、`rewind`等函数的使用方法,并通过示例代码展示了如何进行文件的读写操作。最后,还介绍了如何判断文件读取结束的原因,帮助读者更好地理解和应用文件操作技术。
35 2
|
1月前
|
存储 C语言
C语言文件操作(2)
【10月更文挑战第2天】
|
1月前
|
程序员 编译器 C语言
C语言底层知识------文件操作
本文详细介绍了文件操作的基本概念,包括文件的分类(程序文件和数据文件,其中着重于数据文件的文本文件和二进制文件),流的概念及其在C程序中的应用,以及标准输入输出流stdin、stdout和stderr的作用。作者通过示例展示了如何使用fopen、fclose和常见的读写函数如fgetc、fputc和fgets进行文件操作。
22 2
|
2月前
|
C语言
C语言——文件操作
本文介绍了文件的基本操作,包括文件的打开、关闭、读取和写入。使用`fopen`函数以不同模式(如“r”、“w”等)打开文件,并通过`fclose`关闭。文章详细解释了如何利用`fputc`、`fputs`及`fprintf`进行格式化写入,同时介绍了`fgetc`、`fgets`和`fscanf`用于文件内容的读取。此外,还涵盖了二进制文件的读写方法以及如何通过`fseek`、`ftell`和`rewind`实现文件的随机访问。
51 1
C语言——文件操作
|
1月前
|
存储 缓存 编译器
文件操作——C语言
文件操作——C语言
|
1月前
|
存储 C语言
简述C语言文件操作
简述C语言文件操作
11 0
|
1月前
|
存储 文件存储 C语言
深入C语言:文件操作实现局外影响程序
深入C语言:文件操作实现局外影响程序
|
1月前
|
存储 程序员 编译器
C语言文件操作(1)
【10月更文挑战第1天】
|
1月前
|
存储 C语言
C语言的文件操作
C语言的文件操作
22 0
|
1月前
|
存储 移动开发 Unix
C 语言文件操作详解
C 语言文件操作详解