【C语言】文件操作-2

简介: 【C语言】文件操作-2

四、文本文件和二进制文件


根据数据的组织形式,我们将数据文件分为文本文件和二进制文件


数据在内存中以二进制的形式存储,如果不加转换的输出到外存,那就是二进制文件,如果我们将数据的形式转换为ascll码的话,那就是文本文件


值得注意的是,字符在内存中均以ascll码的形式存储,数值型数据既可以用ascll形式存储,也可以用二进制形式存储


497b392a58684c3e97cf6aeaf6c3f3f6.png


当用ascll形式存储时,我们会将10000看成5个字符,我们将这5个字符所对应的ascll码值,存储到内存里面

当用二进制形式存储时,10000其实就是个整型,我们将它按照4字节32比特位存储即可


五、文件的随机读写

前面给大家介绍的fgetc,fputc,fgets,fputs,fscanf,fprintf,fread,fwrite等操作文件的函数,其返回的指针是有统一顺序的,他的文件指针都是指向文件内容的第一个信息数据的地址的。


这里我们给大家介绍一下,能够改变文件指针指向位置的三个函数



5.1 fseek


a88d22d5db254b70b78528cacf08eb97.png


int main()
{
  FILE* pf = fopen("test.txt", "r");//以只读的方式打开文件test.txt
  if (pf == NULL)
  {
    printf("%s\n", strerror(errno));
  }
  //1.定位文件指针
  fseek(pf, -2, SEEK_END); 
    //2.读取文件
  int ch = fgetc(pf);//从pf指向的文件中读取内容
  printf("%c", ch);
  //3.关闭文件 
  fclose(pf);
  pf = NULL;
  return 0;
}


这里的fseek可以调整指针位置,以当前位置为起点,移动特定的偏移量到我们想要的位置


5.2 ftell


67f00a2d945142fd912c96f851216e69.png


函数具体功能实现:

int main()
{
  FILE* pf = fopen("test.txt", "r");
  if (pf == NULL)
  {
    printf("%s\n", strerror(errno));
  }
  int ch = fgetc(pf);//从pf指向的文件中读取第一个字符,相应的指针位置相对于起始量偏移了1
  int h = fgetc(pf);//偏移了2
  int pos = ftell(pf);//所以这里的ftell返回值应该是2
  printf("%d\n", pos);//结果应为2
  return 0;
}


我们这里的ftell函数作用起始就是返回当前文件指针相对于起始位置的偏移量

5.3 rewind


1c63b9901130450f9252eb4a21e5b5f0.png


函数功能实现:

int main()
{
  FILE* pf = fopen("test.txt", "r");
  if (pf == NULL)
  {
    printf("%s\n", strerror(errno));
  }
  int ch = fgetc(pf);
  int h = fgetc(pf);
  int pos = ftell(pf);
  printf("%d\n", pos);//结果为2
  rewind(pf);//我们这里让文件位置重新回到起始位置
  pos = ftell(pf);//然后再用ftell返回当前文件指针的偏移量大小
  printf("%d\n", pos);//返回到起始位置后,结果为0
  return 0;
}


所以这个函数功能也是比较简单的,就是重置我们的文件指针指向的位置,让他回到起始位置

六、文件读取结束的判定

6.1 feof的错误使用


Tests for end-of-file on a stream.这个是feof的函数介绍,我们可以知道,这个函数是用来测试文件结束形式的。所以这个函数不是用来判断文件是否结束的,而是用来判定文件是如何结束的,到底是因为读取到\0结束的?还是因为其他原因导致文件读取错误,而导致文件结束的?


所以很多人看到feof(end of file)时会把他认为成一个判断文件是否结束的函数,但其实不是这样的The feof function returns a nonzero value after the first read operation that attempts to read past the end of the file. It returns 0 if the current position is not end of file. There is no error return.通过这里的feof函数的返回值介绍(如果当前位置不是文件末尾则返回一个0(有可能发生了读取文件错误),如果成功读取结束的话,将返回一个非0值),我们就可以明白了,这个函数的确是用来测试文件读取结束的方式的,既有可能是读取错误导致的结束,也有可能是读到文件末尾,从而导致的读取结束

6.2 ferror、perror、strerror的对比


35779e3f708143cfa19b29675025c52a.png


perror ( )用 来 将 上 一 个 函 数 发 生 错 误 的 原 因 输 出 到 标 准 错误 (stderr) 。参数 s 所指的字符串会先打印出,后面再加上错误原因字符串。此错误原因依照全局变量errno 的值来决定要输出的字符串。

在库函数中有个error变量,每个error值对应着以字符串表示的错误类型。当你调用"某些"函数出错时,该函数已经重新设置了error的值。perror函数只是将你输入的一些信息和现在的error所对应的错误一起输出。


1.ferror(fault error)的功能: 测试流上的错误。如果流上没有发生错误,ferror返回0。否则,它返回一个非零值。

2.perror的功能: 直接打印错误信息(里面包含我们所输入的信息和错误码所对应的信息一并打印出来)

3.strerror的功能: 把错误码对应的错误信息的字符串地址返回(配合errno使用,errno是一个全局变量,当出现错误时,errno会对应一个库中错误信息对应的错误码,然后我们再用strerror打印这个错误码对应的错误信息)


6.3 判断文件结束的两个例子

6.3.1 文本文件的判断

文本文件的例子:
int main(void)
{
  int c; // 注意:int,非char,要求处理EOF
  FILE* fp = fopen("test.txt", "r");
  if (!fp) //fp是空指针的时候,进入到if语句,输出错误信息
    {
    perror("File opening failed");
    return  ;
  }
  //fgetc 当读取失败的时候或者遇到文件结束的时候,都会返回EOF
  while ((c = fgetc(fp)) != EOF) // 标准C I/O读取文件循环
  {
        //这里循环的条件就是,读取的字符不是EOF,一直将字符输出
    putchar(c);
  }
    //文件读取之后结束了,然后判断是什么原因结束的
  if (ferror(fp))//发生错误,返回一个非0值,进入if语句,打印读取失败的信息
    puts("I/O error when reading");
    //在读取文件时,input或output发生错误
  else if (feof(fp))
    //如果函数feof返回非0值,说明是遇到了EOF结束的,如果当前的位置不是文件末尾,则返回0,也就不是遇到EOF
    puts("End of file reached successfully");
  fclose(fp);
}


自己实现相应的代码,加深理解
int main()
{
    FILE* pf = fopen("test.txt", "r");
    if (pf == NULL)
    {
        return 0;
    }
    //读文件
    int ch = 0;
    while ((ch = fgetc(pf)) != EOF)
    {
        putchar(ch);
    }
    printf("\n");
    //跳出循环,判断是怎么结束的???
    if (ferror(pf))//是读取失败结束???
    {
        printf("error\n");
    }
    else if (feof(pf))//还是遇到文件尾结束???
    {
        printf("end of file\n");
    }
    fclose(pf);
    pf = NULL;
    return 0;
}
总结:所以ferror和feof要配合使用,以此来判断是读取失败结束还是遇到文件尾结束
ferror如果检测没有错误返回0 有错误返回非0值
feof如果没到文件尾的话他会返回一个0,到达文件尾返回一个非0值

6.3.2二进制文件的判断

//二进制文件例子:
#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 的数组到pf流里面去
    fclose(fp);//然后关闭文件
    double b[SIZE];
    fp = fopen("test.bin", "rb");
    size_t ret_code = fread(b, sizeof * b, SIZE, fp); //  将从fp流中读取的数据放到double数组b里面(以二进制的形式读出来)
    if (ret_code == SIZE)
    //如果返回值等于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))
 //(到达文件尾返回一个非0值进入if语句,但它并非我是所预取的文件结束位置,虽然我的预期有可能是错误的,但你返回值<SIZE,我认为这就是unexpected的)
        {
            printf("Error reading test.bin: unexpected end of file\n");
            //提前阅读文件结束,导致返回值小于SIZE,这时unexpected end of file非预期文件结束
        }
        else if (ferror(fp)) 
        {
            perror("Error reading test.bin");//读取错误导致文件读取结束
        }
    }
    fclose(fp);
}



6.4文本文件和二进制文件的对比


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

例如:

fgetc判断是否为EOF(fgetc返回读取为int的字符,或返回EOF以指示错误或文件结束)


fgets判断是否为NULL(返回NULL表示错误或文件结束条件,使用feof或ferror来确定是否发生了错误)


(2)二进制文件的读取结束判断,判断返回值是否小于实际要读的个数

例如:fread判断返回值是否小于实际要读的个数

(Fread返回实际读取的完整项数,如果发生错误或在达到count之前遇到文件结束,则该数可能小于count)



















相关文章
|
15天前
|
存储 程序员 C语言
【C语言】文件操作函数详解
C语言提供了一组标准库函数来处理文件操作,这些函数定义在 `<stdio.h>` 头文件中。文件操作包括文件的打开、读写、关闭以及文件属性的查询等。以下是常用文件操作函数的详细讲解,包括函数原型、参数说明、返回值说明、示例代码和表格汇总。
37 9
|
17天前
|
存储 数据管理 C语言
C 语言中的文件操作:数据持久化的关键桥梁
C语言中的文件操作是实现数据持久化的重要手段,通过 fopen、fclose、fread、fwrite 等函数,可以实现对文件的创建、读写和关闭,构建程序与外部数据存储之间的桥梁。
|
19天前
|
算法 C语言
C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项
本文深入讲解了C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项,通过实例演示了文件操作的基本流程,帮助读者掌握这一重要技能,提升程序开发能力。
60 3
|
1月前
|
存储 C语言
【c语言】玩转文件操作
本文介绍了C语言中文件操作的基础知识,包括文件的打开和关闭、文件的顺序读写、文件的随机读写以及文件读取结束的判定。详细讲解了`fopen`、`fclose`、`fseek`、`ftell`、`rewind`等函数的使用方法,并通过示例代码展示了如何进行文件的读写操作。最后,还介绍了如何判断文件读取结束的原因,帮助读者更好地理解和应用文件操作技术。
39 2
|
2月前
|
存储 编译器 C语言
如何在 C 语言中判断文件缓冲区是否需要刷新?
在C语言中,可以通过检查文件流的内部状态或使用`fflush`函数尝试刷新缓冲区来判断文件缓冲区是否需要刷新。通常,当缓冲区满、遇到换行符或显式调用`fflush`时,缓冲区会自动刷新。
|
2月前
|
存储 编译器 C语言
C语言:文件缓冲区刷新方式有几种
C语言中文件缓冲区的刷新方式主要包括三种:自动刷新(如遇到换行符或缓冲区满)、显式调用 fflush() 函数强制刷新、以及关闭文件时自动刷新。这些方法确保数据及时写入文件。
|
2月前
|
存储 C语言
C语言文件操作(2)
【10月更文挑战第2天】
|
3月前
|
C语言
C语言——文件操作
本文介绍了文件的基本操作,包括文件的打开、关闭、读取和写入。使用`fopen`函数以不同模式(如“r”、“w”等)打开文件,并通过`fclose`关闭。文章详细解释了如何利用`fputc`、`fputs`及`fprintf`进行格式化写入,同时介绍了`fgetc`、`fgets`和`fscanf`用于文件内容的读取。此外,还涵盖了二进制文件的读写方法以及如何通过`fseek`、`ftell`和`rewind`实现文件的随机访问。
53 1
C语言——文件操作
|
2月前
|
程序员 编译器 C语言
C语言底层知识------文件操作
本文详细介绍了文件操作的基本概念,包括文件的分类(程序文件和数据文件,其中着重于数据文件的文本文件和二进制文件),流的概念及其在C程序中的应用,以及标准输入输出流stdin、stdout和stderr的作用。作者通过示例展示了如何使用fopen、fclose和常见的读写函数如fgetc、fputc和fgets进行文件操作。
29 2
|
2月前
|
存储 缓存 编译器
文件操作——C语言
文件操作——C语言