【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)



















相关文章
|
1天前
|
存储 程序员 编译器
文件操作(C语言)
文件操作(C语言)
|
1天前
|
存储 C语言
【c语言】详解文件操作(二)
【c语言】详解文件操作(二)
7 0
|
1天前
|
存储 程序员 编译器
【c语言】详解文件操作(一)
【c语言】详解文件操作(一)
4 0
|
2天前
|
C语言 Windows
【C语言】:文件读写相关函数介绍
【C语言】:文件读写相关函数介绍
8 0
|
2天前
|
编译器 程序员 Linux
|
3天前
|
C语言
C语言——文件操作
C语言——文件操作
16 2
C语言——文件操作
|
12天前
|
C语言
【C语言基础】:文件操作详解(后篇)-2
【C语言基础】:文件操作详解(后篇)
|
12天前
|
存储 C语言
【C语言基础】:文件操作详解(后篇)-1
【C语言基础】:文件操作详解(后篇)
|
12天前
|
存储 C语言 C++
【C语言基础】:文件操作详解(前篇:准备知识)
【C语言基础】:文件操作详解(前篇:准备知识)
|
12天前
|
存储 C语言 Windows
C语言——文件操作
C语言——文件操作
9 0