当前位置:   article > 正文

C语言——文件操作_打印指针的内容

打印指针的内容

1.为什么使用文件

使用文件可以存放数据,使里面的内容永久保存下来,下次打开的时候不会丢失

2.什么是文件

磁盘上的文件就是文件

但程序设计中,主要分为程序文件和数据文件

2.1程序文件

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

2.2数据文件

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

2.3 文件名

一个文件要有唯一的文件标识(文件名),以便用户识别和引用。

文件名包括三部分:文件路径+文件名主干+文件后缀

例:c:code\test.txt 其中c:code是文件路径,test.txt是文件名主干和文件后缀

3.文件的打开和关闭

3.1文件指针

关键的概念是“文件类型指针”,简称“文件指针”。

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

 

fopen

可以搜一下MSDN来搜其功能

在操纵其他文件的路径的话要在文件名前加上绝对路径,否则只会在运行程序当前的路径新建。(ps:注意下方的w装的是双引号

  1. int main()
  2. {
  3. FILE* pf = fopen("test.txt","w");
  4. if(NULL==pf)
  5. {
  6. printf("打开文件失败\n");
  7. return 0;
  8. }
  9. return 0;
  10. }

pf是一个指向FILE类型数据的指针变量。可以使pf指向某个文件的文件信息区(是一个结构体变量)。通过该文件信息区中的信息就能够访问该文件。也就是说,通过文件指针变量能够找到与它关联的文件。

当出现error时,会返回一个空指针

3.2文件的打开和关闭

fclose

  1. int main()
  2. {
  3. //打开文件
  4. FILE* pf = fopen("test.txt","w");
  5. if(NULL==pf)
  6. {
  7. printf("打开文件失败\n");
  8. return 0;
  9. }
  10. //写文件
  11. //关闭文件
  12. fclose(pf);
  13. pf=NULL;
  14. return 0;
  15. }

4.文件的顺序读写

字符输入函数——fgetc

字符输出函数——fputc

文本行输入函数——fgets

文本行输出函数——fputs

写文件

  1. int main()
  2. {
  3. FILE* pf = fopen("data.txt","w");
  4. if(pf==NULL)
  5. {
  6. printf("%s\n",strerror(errno));
  7. return 0;
  8. }
  9. //写文件
  10. //fputc('a',pf);
  11. //fputc('b',pf);
  12. //fputc('c',pf);
  13. char ch=0;
  14. for(ch='a',ch<='z';ch++)
  15. {
  16. fputc(ch,pf);
  17. }
  18. fclose(pf);
  19. pf=NULL;
  20. }

A:我们都知道,对文件进行操作的表现是需要用代码来进行输入以及输出的,但是为什么c语言程序输出到屏幕时不需要写什么代码?

Q:C语言程序,只有运行起来。就默认打开三个流:

FILE*类型:stdin-标准输入流    stdout-标准输出流     stderr-标准错误流

所以才能直接在屏幕上出现

所以,当我们在使用fputc中使用pf时,为文件流,在文件中输出,将这一行代码的pf改为strout标准输出流,就会在屏幕上打印出来。


读文件

fgetc()——字符输入函数—— int fgetc(FILE* stream)

  1. (接上面)
  2. int ch=fgetc(pf);
  3. printf("%c\n",ch);
  4. //继续往下读
  5. int ch=fgetc(pf);
  6. printf("%c\n",ch);
  7. //继续往下读
  8. int ch=fgetc(pf);
  9. printf("%c\n",ch);
  10. int ch=fgetc(pf);
  11. printf("%c\n",ch);

这个可以一直读,直到读完了,就返回EOF,或者读取中途出现错误,也返回EOF

  1. while((ch=fgetc(pf))!=EOF)
  2. {
  3. printf("%c ",ch);
  4. }

fputs——文本行输出操作 int fputs()     (写文件到文本里面去)——标准输出流

写个写一行读一行的操作:

  1. int main()
  2. {
  3. FILE* pf = fopen("data.txt","w");
  4. if(pf==NULL)
  5. {
  6. printf("%s\n",strerror(errno));
  7. return 0;
  8. }
  9. fputs("hello world",pf);
  10. fclose(pf);
  11. pf=NULL;
  12. }

标准输出流:既可以写到文本也可以在屏幕

fputs("hello world",stdout);

读一行:

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

n——空间容纳最大个数,例如放1000进去只会读取999

  1. #define _CRT_SECURE_NO_WARNINGS 1
  2. #include <stdio.h>
  3. int main()
  4. {
  5. FILE* pf = fopen("data.txt", "r");
  6. if (NULL == pf)
  7. {
  8. printf("打开失败\n");
  9. return 0;
  10. }
  11. char arr[1000] = { 0 };
  12. fgets(arr, 1000, pf);
  13. printf("%s\n", arr);
  14. fclose(pf);
  15. pf = NULL;
  16. return 0;
  17. }

写一份文件拷贝

  1. //拷贝文件
  2. #define _CRT_SECURE_NO_WARNINGS 1
  3. #include <stdio.h>
  4. #include <errno.h>
  5. #include <string.h>
  6. int main()
  7. {
  8. FILE* pr = fopen("data.txt", "r");
  9. if (NULL == pr)
  10. {
  11. printf("openning is:%s\n", strerror(errno));
  12. return 0;
  13. }
  14. FILE* pw = fopen("data2.txt", "w");
  15. if (NULL == pw)
  16. {
  17. printf("openning is:%s\n", strerror(errno));
  18. return 0;
  19. }
  20. int ch = 0;
  21. while ((ch = fgetc(pr)) != EOF)
  22. {
  23. fputc(ch, pw);
  24. }
  25. fclose(pr);
  26. pr = NULL;
  27. fclose(pw);
  28. pw = NULL;
  29. return 0;
  30. }

对于结构化数据,有具体格式化数据的,应该怎么输入输出?

fprintf——格式化输出数据——int fprintf( FILE* stream, const char* format [, argument ]...**);

相较于printf,会发现其实只是多一个FILE*罢了

写格式化数据

  1. //格式化数据的输出
  2. #define _CRT_SECURE_NO_WARNINGS 1
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <errno.h>
  6. //假设给上一个结构体:
  7. struct Stu
  8. {
  9. char name[20];
  10. int age;
  11. float score;
  12. };
  13. int main()
  14. {
  15. struct Stu s = { "Lisi",18,90.9 };
  16. FILE* pf = fopen("data.txt", "w");
  17. if (NULL == pf)
  18. {
  19. printf("openning is %s\n", strerror(errno));
  20. return 0;
  21. }
  22. fprintf(pf, "%s %d %.2f", s.name, s.age, s.score);
  23. fclose(pf);
  24. pf = NULL;
  25. return 0;
  26. }

读格式化数据

fscanf——格式化输入数据 ——int fscanf( FILE *stream, const char *****format [, argument ]... );

我们使用这个与scanf比较,又可以发现只是多了一个FILE*

  1. //读格式化数据
  2. #define _CRT_SECURE_NO_WARNINGS 1
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <errno.h>
  6. struct Stu
  7. {
  8. char name[20];
  9. int age;
  10. float score;
  11. };
  12. int main()
  13. {
  14. struct Stu s = { 0 };
  15. FILE* pf = fopen("data.txt", "r");
  16. if (NULL == pf)
  17. {
  18. printf("error is: %s\n", strerror(errno));
  19. }
  20. fscanf(pf, "%s %d %f", s.name, &s.age, &s.score);
  21. printf("%s %d %f\n", s.name, s.age, s.score);
  22. fclose(pf);
  23. pf = NULL;
  24. return 0;
  25. }

二进制输出

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

  1. //以二进制的方式写文件
  2. #define _CRT_SECURE_NO_WARNINGS 1
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <errno.h>
  6. struct Stu
  7. {
  8. char name[20];
  9. int age;
  10. float score;
  11. };
  12. int main()
  13. {
  14. struct Stu s[2] = { {"Zhangsan",18,90.6},{"Lisi",20,95.5} };
  15. FILE* pf = fopen("data.txt", "wb");
  16. if (NULL == pf)
  17. {
  18. printf("openning erroe is %s\n", strerror(errno));
  19. return 0;
  20. }
  21. fwrite(s, sizeof(struct Stu), 2, pf);
  22. fclose(pf);
  23. pf = NULL;
  24. return 0;
  25. }

以二进制的方式读

fread——读取文件 size_t fread( void buffer, size_t size, *size_t count,FILE *****stream );

ps:这里fread的返回值是你读到多少个元素就返回多少值,比如一开始设定读五个,如果有五个,就返回五,如果没有,例如只剩下三个了,就只能返回三。

与上面的二进制方式写入的格式是差不多的

  1. //以二进制方式读
  2. #define _CRT_SECURE_NO_WARNINGS 1
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <errno.h>
  6. struct Stu
  7. {
  8. char name[20];
  9. int age;
  10. float score;
  11. };
  12. int main()
  13. {
  14. struct Stu s[2] = { 0 };
  15. FILE* pf = fopen("data.txt", "rb");
  16. if (NULL == pf)
  17. {
  18. printf("error is%s\n", strerror(errno));
  19. return 0;
  20. }
  21. fread(s, sizeof(struct Stu), 2, pf);
  22. printf("%s %d %f\n", s[0].name, s[0].age, s[0].score);
  23. printf("%s %d %f\n", s[1].name, s[1].age, s[1].score);
  24. return 0;
  25. }

sprintf与sscanf

sprintf——把格式化数据转换成字符串 ——int sprintf( char* buffer, const char* format [, argument] ... );

相比fprintf,sprintf是直接把格式化的数据放到了一个字符串内。

sscanf——与sprintf相似。但是是与sprintf功能相反。将一个字符串按照某些我们写的格式放入结构体之中。 ——int sscanf( const char* buffer, const char* format [, argument ] ... );

ps:这里此时已经与文件相关没有关系了。

  1. //sprintf与sscanf的使用
  2. #define _CRT_SECURE_NO_WARNINGS 1
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <errno.h>
  6. struct Stu
  7. {
  8. char name[20];
  9. int age;
  10. float score;
  11. };
  12. int main()
  13. {
  14. struct Stu s1 = { "Lisi",20,96.6 };
  15. char arr[100] = { 0 };
  16. sprintf(arr, "%s %d %.2f", s1.name, s1.age, s1.score);
  17. printf("%s\n", arr);
  18. struct Stu s2 = { 0 };
  19. sscanf(arr, "%s %d %f", s2.name, &s2.age, &s2.score);
  20. printf("%s %d %.2f\n", s2.name, s2.age, s2.score);
  21. return 0;
  22. }

注意区别:

  • scanf——从标准输入流(stdin)上进行格式化输入的函数
  • printf——向标出输出流(stdout)上进行格式化的输出函数
  • fscnf——可以从标准输入流(stdin)/指定的文件流上读取格式化的数据
  • fprintf——把数据按照格式化的方式输出到标准输出流(stdout)/指定文件流
  • sscanf——可以从一个字符串中提取(转化)出格式化数据
  • sprintf——把一个格式化的数据转换成字符串

总结:

 

5.文件的随机读写

5.1fseek

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

打开文件时用的是指向起始位置,我们可以通过这个函数来调整指向的位置

在正式使用前,要知道几个参数的含义:

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

  • FILE——就是要输入的文件
  • offset——要移动的偏移量大小
  • origin——要怎么样移动

在这里origin又分为一下三种(选择从哪里开始读取):

  • SEEK_SET: 文件开头
  • SEEK_CUR: 当前位置
  • SEEK_END: 文件结尾

ps:当选择END的时候要记得偏移量是负数,因为要倒着数

fseek的实际应用:

输出数据到文件内:

  1. #define _CRT_SECURE_NO_WARNINGS 1
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <errno.h>
  5. //这时在已经创造了一个名为data的txt文件并且已经放入abcdef的情况下写的
  6. int main()
  7. {
  8. char ch = 0;
  9. FILE* pf = fopen("data.txt", "r");
  10. if (NULL == pf)
  11. {
  12. printf("error is%s\n", strerror(errno));
  13. return 0;
  14. }
  15. //单个读取字符
  16. ch = fgetc(pf);//这里读到字符a
  17. printf("%c\n", ch);
  18. ch = fgetc(pf);//这里读到字符b
  19. printf("%c\n", ch);
  20. //指定位置到f
  21. //fseek(pf, 3, SEEK_CUR);//从当前b开始读,往后三个偏移量
  22. //fseek(pf, 5, SEEK_SET);//从起始位置开始往后五个偏移量指向f
  23. fseek(pf, -1, SEEK_END);//从末尾开始,往前一个偏移量指向f
  24. ch = fgetc(pf);//经过移动后,直接跳过读到了字符f
  25. printf("%c\n", ch);
  26. //关闭文件
  27. fclose(pf);
  28. pf = NULL;
  29. return 0;
  30. }

将文件内的数据修改:

  1. //将文件中的某一位置数据给替换掉
  2. #define _CRT_SECURE_NO_WARNINGS 1
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <errno.h>
  6. int main()
  7. {
  8. char ch = 0;
  9. FILE* pf = fopen("data.txt", "w");
  10. if (NULL == pf)
  11. {
  12. printf("error is%s\n", strerror(errno));
  13. return 0;
  14. }
  15. for (ch = 'a'; ch <= 'z'; ch++)//data.txt文件先放入a~z
  16. {
  17. fputc(ch, pf);
  18. }
  19. fseek(pf, -2, SEEK_END);//先指向y的位置
  20. ch = '#';
  21. fputc(ch, pf);//把y位置替换成#
  22. //关闭文件
  23. fclose(pf);
  24. pf = NULL;
  25. return 0;
  26. }

5.2 ftell

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

ftell——long ftell( FILE *stream );

ftell的实际应用

  1. #define _CRT_SECURE_NO_WARNINGS 1
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <errno.h>
  5. //这时在已经创造了一个名为data的txt文件并且已经放入abcdef的情况下写的
  6. int main()
  7. {
  8. FILE* pf = fopen("data.txt", "r");
  9. if (NULL == pf)
  10. {
  11. printf("error is%s\n", strerror(errno));
  12. return 0;
  13. }
  14. char ch = 0;
  15. ch = fgetc(pf);//此时读入的是a
  16. printf("%c\n", ch);
  17. ch = fgetc(pf);//此时读入的是b
  18. printf("%c\n", ch);
  19. //假如此时我们不知道指针已经指向哪里了,那么便可以创造一个变量来存储调用ftell函数返回的指针指向的偏移量的值
  20. int ret = ftell(pf);
  21. printf("%d\n", ret);
  22. fclose(pf);
  23. pf = NULL;
  24. return 0;
  25. }

5.3 rewind

将文件指针指向起始位置

rewind—— void rewind( FILE * );

  1. //假设有一个FILE*变量为pf,此时这个pf代表的文件的指针不知道指向哪里了
  2. rewind(pf);//这个时候就已经把指针提到起始位置了

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

数据文件的分类

数据文件被分为文本文件二进制文件

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

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

数据在内存中的存储

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

例如整数10000:

ASII形式存储:

因为有五个字符,所以会用到五个字节,每个字节存储的是对应数字字符

二进制形式存储:

会将10000转化为二进制来存储,用到四个字节。

 

7.文件读取结束的判定

  1. 文本文件读取是否结束,判断返回值是否为 EOF ( fgetc ),或者 NULL ( fgets ) 例如: fgetc 判断是否为 EOF . fgets 判断返回值是否为 NULL .
  2.  二进制文件的读取结束判断,判断返回值是否小于实际要读的个数。 例如: fread判断返回值是否小于实际要读的个数。
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. int main(void)
  4. {
  5. int c; // 注意:int,非char,要求处理EOF
  6. FILE* fp = fopen("test.txt", "r");
  7. if (!fp) {
  8. perror("File opening failed");
  9. return EXIT_FAILURE;
  10. }
  11. //fgetc 当读取失败的时候或者遇到文件结束的时候,都会返回EOF
  12. while ((c = fgetc(fp)) != EOF) // 标准C I/O读取文件循环
  13. {
  14. putchar(c);
  15. }
  16. //判断是什么原因结束的
  17. if (ferror(fp))//读取失败了,会返回非0值,否则返回0
  18. puts("I/O error when reading");
  19. else if (feof(fp))//当是读完全部正常结束的,会返回非0值,否则是因为其他原因结束的,则返回0
  20. puts("End of file reached successfully");
  21. fclose(fp);
  22. }

8.文件缓冲区

不同编译器的缓冲方式不同

为了让办事效率高,很多代码都会集中在缓冲区,等到缓冲区放满,到一定程度就会一起运行。

当我们写文件的时候,会先放入缓冲区,不会立马写在文件里面,如果要立马再出去缓冲区,可以刷新缓冲区。

刷新缓冲区的函数——fflush

fflush(FILE*)    fclose也可以刷新缓冲区

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/黑客灵魂/article/detail/789589
推荐阅读
相关标签
  

闽ICP备14008679号