文件(下)——“C”

简介: 文件(下)——“C”

各位CSDN的uu们你们好呀,今天,小雅兰的内容是文件的知识点,下面,就让我们进入文件的世界吧


文件的顺序读写


文件的随机读写


               fseek


               ftell


               rewind


文本文件和二进制文件


文件读取结束的判定


文件缓冲区


在上篇博客中,最后,其实我写了关于流的知识点,但是不全面,需要补充一些内容,我们一起来复习一下:


文件(上)——“C”_认真学习的小雅兰.的博客-CSDN博客


文件的顺序读写


流:

73c25609273b4d9b97fa1300ab404d91.png

stdin FILE*
stdout FILE*
stderr FILE*

举个例子:

#define _CRT_SECURE_NO_WARNINGS 1
//stdin FILE*
//stdout FILE*
//stderr FILE*
#include<stdio.h>
int main()
{
  int ch = fgetc(stdin);
  printf("%c\n", ch);
  return 0;
}

679f7683ae2442da9bf00757464e48b7.png

#define _CRT_SECURE_NO_WARNINGS 1
//stdin FILE*
//stdout FILE*
//stderr FILE*
#include<stdio.h>
int main()
{
  fputc('a', stdout);
  fputc('b', stdout);
  fputc('c', stdout);
  fputc('d', stdout);
  return 0;
}

48e0acdb28f648f284a761a4362c4cb0.png

对比一组函数:

scanf/fscanf/sscanf

printf/fprintf/sprintf

37d940c575c6485cb0ec4c6a6662c0af.png

7c8926fb40ed41b9af46fdf3d04a6a64.png

6ed31751133a42dc94376b263bebf2b9.png

9d526ffbb4d747fca8711edb27f915ca.png

#include<stdio.h>
struct S
{
  int n;
  float f;
  char arr[20];
};
int main()
{
  struct S s = { 520,3.5f,"wangwu" };
  //把一个结构体转化成字符串
  char arr[200] = { 0 };
  sprintf(arr, "%d %f %s\n", s.n, s.f, s.arr);
  printf("%s\n", arr);
  return 0;
}

de392220f7e74a92b2ae814d3839b16e.png

86a1da0ca6d643b2973c532b78206436.png

f65c37a8d5f8415ab438332037892173.png

#include<stdio.h>
struct S
{
  int n;
  float f;
  char arr[20];
};
int main()
{
  struct S s = { 520,3.5f,"wangwu" };
  //把一个结构体转化成字符串
  char arr[200] = { 0 };
  sprintf(arr, "%d %f %s\n", s.n, s.f, s.arr);
  printf("字符串的数据:%s\n", arr);
  //把一个字符串转换成对应的格式化数据
  struct S tmp = { 0 };
  sscanf(arr, "%d %f %s\n", &(tmp.n),&(tmp.f), tmp.arr);
  printf("格式化的数据:%d %f %s\n", tmp.n, tmp.f, tmp.arr);
  return 0;
}

df0c7ecf2e93404caeee9a1120991374.png

06037871e4af418082cae5cb1faf7765.png

二进制:

3f3692f009cc43eaba47af7a315a5264.png

f95f3d0449f54c1b8b0e87655c7eea27.png

c079a963e0f9468d825bad412501319f.png

ac81854f2d0f47819e66282133b22885.png

#include<stdio.h>
struct S
{
  char name[20];
  int age;
  float score;
};
int main()
{
  struct S s = { "zhangsan",20,95.5f };
  FILE* pf = fopen("C:\\Users\\86137\\Desktop\\sss.txt.txt", "wb");
  if (pf == NULL)
  {
    perror("fopen");
    return 1;
  }
  //写文件
  fwrite(&s,sizeof(struct S),1,pf);
  //关闭文件
  fclose(pf);
  pf = NULL;
  return 0;
}

6d16c45a6e384a8ca29449c6d9be5f5d.png

这样的原因就是:是以二进制的形式写出来的

90080083073b49babca0e832d66aa38c.png

c7c4f78c99c540f39f47c7218dbfbe93.png

#include<stdio.h>
struct S
{
  char name[20];
  int age;
  float score;
};
int main()
{
  struct S s = { 0 };
  FILE* pf = fopen("C:\\Users\\86137\\Desktop\\sss.txt.txt", "rb");
  if (pf == NULL)
  {
    perror("fopen");
    return 1;
  }
  //读文件
  fread(&s, sizeof(struct S), 1, pf);
  printf("%s %d %f\n", s.name, s.age, s.score);
  //关闭文件
  fclose(pf);
  pf = NULL;
  return 0;
}

7417b84798d049ecb7348ff2f56f22e8.png

文件的随机读写

fseek

a0118edd40d14195ae58836efb299ef8.png

7daebe9ca62c483298dbf9b2a0184247.png

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

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

bd0aea91541b477fbbb3769f72cec00b.png

下面,来使用一下该函数:

b6d83294e15144ee85b23b49708cbd2b.png

#include<stdio.h>
int main()
{
  //打开文件
  FILE* pf = fopen("C:\\Users\\86137\\Desktop\\sss.txt.txt", "r");
  if (pf == NULL)
  {
    perror("fopen");
    return 1;
  }
  //读文件
  int ch = fgetc(pf);
  printf("%c\n", ch);//a
  ch = fgetc(pf);
  printf("%c\n", ch);//b
  ch = fgetc(pf);
  printf("%c\n", ch);//c
  ch = fgetc(pf);
  printf("%c\n", ch);//d
  fseek(pf, -3, SEEK_CUR);
  ch = fgetc(pf);
  printf("%c\n", ch);//希望读到的是b
  //关闭文件
  fclose(pf);
  pf = NULL;
  return 0;
}

9cd51fa7f5e84879877d867f549642b6.png

ftell

f709538f13cd423796c5e5b20e619e32.png

9f820b1ac2964c409e388d7d0ff6bbb6.png

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

               long int ftell ( FILE * stream );

下面,还是来使用一下该函数:

#include<stdio.h>
int main()
{
  //打开文件
  FILE* pf = fopen("C:\\Users\\86137\\Desktop\\sss.txt.txt", "r");
  if (pf == NULL)
  {
    perror("fopen");
    return 1;
  }
  //读文件
  int ch = fgetc(pf);
  printf("%c\n", ch);//a
  ch = fgetc(pf);
  printf("%c\n", ch);//b
  ch = fgetc(pf);
  printf("%c\n", ch);//c
  ch = fgetc(pf);
  printf("%c\n", ch);//d
  printf("%d\n", ftell(pf));
  //关闭文件
  fclose(pf);
  pf = NULL;
  return 0;
}

b7913c1201e345fc912d122afb5bf5fd.png

rewind1cad78bf779440d1856dc5cd7b32290c.png

4db00dad2bac40a2a580bc797ea0c11a.png

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

               void rewind ( FILE * stream );

下面,还是来使用一下该函数:

#include<stdio.h>
int main()
{
  //打开文件
  FILE* pf = fopen("C:\\Users\\86137\\Desktop\\sss.txt.txt", "r");
  if (pf == NULL)
  {
    perror("fopen");
    return 1;
  }
  //读文件
  int ch = fgetc(pf);
  printf("%c\n", ch);//a
  ch = fgetc(pf);
  printf("%c\n", ch);//b
  ch = fgetc(pf);
  printf("%c\n", ch);//c
  ch = fgetc(pf);
  printf("%c\n", ch);//d
  rewind(pf);
  printf("%d\n", ftell(pf));
  ch = fgetc(pf);
  printf("%c\n", ch);
  //关闭文件
  fclose(pf);
  pf = NULL;
  return 0;
}

bc007b637e8f4fb3b47808465a71479e.png

文本文件和二进制文件


根据数据的组织形式,数据文件被称为文本文件或者二进制文件。


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


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


一个数据在内存中是怎么存储的呢?


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


如有整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占用5个字节(每个字符一个字节),而二进制形式输出,则在磁盘上只占4个字节(VS2013测试)。

2be61d77774549d1a0650ba54f0ecabc.png

005baad8bdfd4d2cbb65a4c901536754.png

#include <stdio.h>
int main()
{
  int a = 10000;
  FILE* pf = fopen("test.txt", "wb");
  fwrite(&a, 4, 1, pf);//二进制的形式写到文件中
  fclose(pf);
  pf = NULL;
  return 0;
}

a793a8929e684fe796c2d9e6ef969540.png

e2928d7c704347459c6a53e540b9d920.png

文件读取结束的判定


被错误使用的feof


牢记:在文件读取过程中,不能用feof函数的返回值直接用来判断文件的是否结束。


feof的作用是:当文件读取结束的时候,判断是读取结束的原因是否是:遇到文件尾结束。


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


fgetc 判断是否为 EOF .

fgets 判断返回值是否为 NULL .

02cf665296654fbfbd0c3c7ed908acd7.png

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

  • fread判断返回值是否小于实际要读的个数。

正确的使用:

文本文件的例子:

#include <stdio.h>
#include <stdlib.h>
int main()
{
  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);
}

二进制文件的例子:

#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);
}

文件缓冲区


ANSIC 标准采用“缓冲文件系统”处理的数据文件的,所谓缓冲文件系统是指系统自动地在内存中为程序 中每一个正在使用的文件开辟一块“文件缓冲区”。


从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓冲区的大小根据C编译系统决定的。

b745d8bde8c34b7bb4b73d4f5e086c07.png

08fdfec1e06440568bd70b9d8c68dbb8.png

证明缓冲区的存在:

#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语言在操作文件的时候,需要做刷新缓冲区或者在文件操作结束的时候关闭文件。 如果不做,可能导致读写文件的问题。


实现一个代码,拷贝一个文件

#include <stdio.h>
int main()
{
  //打开文件
  //打开被读的文件
  FILE* pfRead = fopen("test1.txt", "r");
  if (pfRead == NULL)
  {
    perror("open file for read");
    return 1;
  }
  //打开要写的文件
  FILE* pfWrite = fopen("test2.txt", "w");
  if (pfWrite == NULL)
  {
    fclose(pfRead);
    pfRead = NULL;
    pfRead = NULL;
    perror("open file for write");
    return 1;
  }
  //拷贝
  int ch = 0;
  while (ch = fgetc(pfRead) != EOF)
  {
    fputc(ch, pfWrite);
  }
  //关闭文件
  fclose(pfRead);
  pfRead = NULL;
  fclose(pfWrite);
  pfWrite = NULL;
  return 0;
}

好啦,小雅兰的文件知识点到这里就完完整整结束啦,还要继续加油噢!!!

772aa2904b5b4056b2f414e0616cf749.jpg

相关文章
|
6月前
|
存储 Java 程序员
文件的介绍
文件的介绍
111 1
|
6月前
|
Windows
HiBit Uninstaller v3.2.10单文件版
HiBit Uninstaller是一款免费无广告功能强大的软件卸载程序,有强制卸载、批量卸载程序、Windows应用商店Appx管理器、Windows更新补丁管理器、浏览器扩展管理器、注册表清理、磁盘垃圾文件清理、快捷方式修复、文件粉碎程序、进程管理器、启动项管理器、系统服务管理器、计划任务管理器、资源管理器菜单项管理器、Windows系统还原管理器等功能。
50 2
|
6月前
|
Windows
Hasleo EasyUEFI v5.5单文件版
Hasleo EasyUEFI,轻松管理EFI/UEFI启动项 & 管理EFI系统分区 & 修复EFI系统启动问题!EasyUEFI是免费EFI启动管理软件,用于管理EFI/UEFI启动项,包括创建、删除、编辑、清理、备份和还原EFI/UEFI启动项。
77 0
|
6月前
|
存储 内存技术
什么是文件
什么是文件
155 0
|
NoSQL Python
PythonExcel文件
在Python中,我们可以使用许多库来处理Excel文件,其中最常用的是pandas和openpyxl。
84 0
|
数据安全/隐私保护
p文件如何转为m文件
如果你是MATLAB爱好者,你一定知道MATLAB P文件,但是,你是否也和许多人一样,摸不着头脑?难道你也经常遇到MATLAB P文件加密问题,难以阅读和研究吗?那么,你需要一个MATLAB P文件解密工具!
|
编译器 数据库 C语言
文件(上)——“C”
文件(上)——“C”
|
C#
C#生成anb文件
C#生成anb文件
132 0
C#生成anb文件
|
存储
Fasta和Fastq文件
Fasta和Fastq文件
251 0
小技巧——对比两个文件是否相同
小技巧——对比两个文件是否相同
120 0