目录

  • 一、文件
    • 1、以文件功能分类:
    • 2、文件名
  • 二、文件指针
  • 三、文件的打开和关闭
    • 1、fopen fclose
    • 2、"r" - 读
    • 3、"w" - 写
  • 四、顺序读写
    • 1、有哪些函数
    • 2、fputc - 字符输出(写)
      • 2.1、所有输出流
    • 3、fgetc - 字符输入(读)
      • 3.1、从文件里读
      • 3.2、从标准输入读
    • 4、对比putchar printf getchar scanf
    • 5、fputs - 文本输出(写)
    • 6、fgets - 文本输入(读)
      • 使用示例:
    • 7、fprintf - 格式化输出
    • 8、fscanf - 格式化输入
    • 9、fwrite - 二进制输出
    • 10、fread - 二进制输入
    • 11、对比一组函数
      • sscanf 与 sprintf
    • 优化通讯录程序
  • 五、文件的随机读写
    • 1、fseek
    • 2、ftell
    • 3、rewind
  • 六、文本文件和二进制文件
  • 七、文件结束判定
    • feof
  • 八、文件缓冲区

一、文件

什么是文件:

磁盘上的文件就是文件

1、以文件功能分类:

程序文件:

源程序文件test.c 目标文件test.obj 可执行程序test.exe

数据文件:

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

2、文件名

一个文件要有一个唯一的文件标识,以便用户识别和引用。
文件名包含3部分:文件路径+文件名主干+文件后缀
例如: c:\code\test.txt
为了方便起见,文件标识常被称为文件名。



二、文件指针

每一个打开的文件都会后一个与它匹配的文件信息区,存储文件信息
这些信息保存在一个结构体变量中,如:struct FILE f;。该结构体类型是有系统声明的,取名FILE.

例如,VS2008编译环境提供的 stdio.h 头文件中有以下的文件类型声明:

struct _iobuf {char *_ptr;
int _cnt;
char *_base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char *_tmpfname;
};
typedef struct _iobuf FILE;

每当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息,使用者不必关心细节。
一般都是通过一个FILE的指针来维护这个FILE结构的变量,这样使用起来更加方便。



三、文件的打开和关闭

1、fopen fclose

ANSIC 规定使用fopen函数来打开文件,fclose来关闭文件。



2、“r” - 读

#include <stdio.h>int main()
{FILE* pf = fopen("data.txt", "r");if (pf == NULL){perror("fopen"); // 输出:// fopen: No such file or directory// 因为文件不存在return -1;}// 读文件// 关闭文件fclose(pf);pf = NULL;return 0;
}

绝对路径

#include <stdio.h>int main()
{FILE* pf = fopen("C:\\Users\\Chloe\\Desktop\\data.txt", "r"); // 绝对路径// FILE* pf = fopen("data.txt", "r"); // 相对路径if (pf == NULL){perror("fopen");return -1;}// 读文件// 关闭文件fclose(pf);pf = NULL;return 0;
}


3、“w” - 写

#include <stdio.h>int main()
{FILE* pf = fopen("C:\\Users\\Chloe\\Desktop\\data.txt", "w"); // 会生成一个文件if (pf == NULL){perror("fopen");return -1;}// 读文件// 关闭文件fclose(pf);pf = NULL;return 0;
}


四、顺序读写

1、有哪些函数

fputc - 字符输出函数 写一个字符
fgetc - 字符输入函数 读一个字符



2、fputc - 字符输出(写)

int fgetc( FILE *stream );

#include <stdio.h>int main()
{FILE* pf = fopen ("C:\\Users\\Chloe\\Desktop\\data.txt", "w");if (NULL == pf){perror("fopen");return -1;}// 写文件fputc('b', pf); // 在data.txt中写入bitfputc('i', pf);fputc('t', pf);// 关闭文件fclose(pf);pf = NULL;return 0;
}

2.1、所有输出流

流:高度抽象的概念

 C语言的程序,只要运行起来,就默认打开了三个流:stdout - 标准输出流stdin  - 标准输入流stderr - 标准错误流类型都是 FILE*

#include <stdio.h>int main()
{fputc('b', stdout);fputc('i', stdout);fputc('t', stdout);
}



3、fgetc - 字符输入(读)

int fputc( int c, FILE *stream );


3.1、从文件里读

把文件内容改成abcdef 会输出什么?

#include <stdio.h>int main()
{FILE* pf = fopen ("C:\\Users\\Chloe\\Desktop\\data.txt", "r");if (NULL == pf){perror("fopen");return -1;}// 读文件int ch = fgetc(pf);                                            printf("%c\n", ch); // ach = fgetc(pf);printf("%c\n", ch); // bch = fgetc(pf);printf("%c\n", ch); // c// 关闭文件fclose(pf);pf = NULL;return 0;
}

3.2、从标准输入读

也可以从标准输入读,也就是键盘

#include <stdio.h>int main()
{int ch = fgetc(stdin);printf("%c\n", ch);ch = fgetc(stdin);printf("%c\n", ch);ch = fgetc(stdin);printf("%c\n", ch);}



4、对比putchar printf getchar scanf

#include <stdio.h>int main()
{fputc('b', stdout);// putchar printf("%c", ch);int ch = fgetc(stdin);// getchar scanf("%c", ch);printf("%c\n", ch);
}


5、fputs - 文本输出(写)

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

把数据放进流里

#include <stdio.h>int main()
{FILE* pf = fopen("data.txt", "w");if (NULL == pf){perror("fopen");return -1;}// 写文件// 写一行数据fputs("hello world\n", pf);fputs("hello bit\n", pf);fclose(pf);pf = NULL;
}



6、fgets - 文本输入(读)

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

从流里读数据


使用示例:

想要读5个字符,但实际只读了4个字符,因为后面后有一个 \0

改成20:



7、fprintf - 格式化输出

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

与 printf 函数对比

示例:

#include <stdio.h>struct S
{int n;double d;
};int main()
{struct S s = { 100, 3.14 };FILE* pf = fopen("data.txt", "w");if (NULL == pf){perror("fopen");return -1;}// 写文件fprintf(pf, "%d %lf", s.n, s.d);// 关闭文件fclose(pf);pf = NULL;return 0;
}



8、fscanf - 格式化输入

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

与 printf 函数对比

示例:

#include <stdio.h>struct S
{int n;double d;
};int main()
{struct S s = { 0 };FILE* pf = fopen("data.txt", "r");if (NULL == pf){perror("fopen");return -1;}// 读文件fscanf(pf, "%d %lf", &(s.n), &(s.d));printf("%d %lf", s.n, s.d);// 关闭文件fclose(pf);pf = NULL;return 0;
}



9、fwrite - 二进制输出

示例:

wb”(只写) 为了输出数据,打开一个二进制文件

#include <stdio.h>struct S
{int n;double d;char name[10];
};int main()
{struct S s = { 100, 3.24, "zhangsan"};FILE* pf = fopen("data.txt", "wb");if (NULL == pf){perror("fopen");return -1;}// 以二进制方式写fwrite(&s, sizeof(s), 1, pf);// 关闭文件fclose(pf);pf = NULL;return 0;
}

文件内输出一堆二进制



10、fread - 二进制输入

示例:

#include <stdio.h>struct S
{int n;double d;char name[10];
};int main()
{struct S s = { 100, 3.24, "zhangsan" };FILE* pf = fopen("data.txt", "rb");if (NULL == pf){perror("fopen");return -1;}// 读文件 - 以二进制方式读fwrite(&s, sizeof(s), 1, pf);// 打印文件printf("%d %lf %s\n", s.n, s.d, s.name); // 100 3.240000 zhangsan// 关闭文件fclose(pf);pf = NULL;return 0;
}


11、对比一组函数

scanf/fscanf/sscanf
printf/fprintf/sprintf

scanf:从标准输入流(键盘)读取格式化的数据
printf:把格式化的数据输出到标准输出(屏幕)上

fscanf:从所有的输入流读取格式化的数据
fprintf:把格式化的数据输出到所有输出流(屏幕 / 文件)上

剩下 sscanf 和 sprintf 是什么意思?



sscanf 与 sprintf

从一个字符串里读格式化的数据
写格式化的数据到字符串里

举例:

#include <stdio.h>struct S
{int n;double d;char name[10];
};int main()
{char arr[100] = { 0 };struct S s = { 100, 3.14, "zhangsan" };// 把一个格式化的数据转换成字符串sprintf(arr, "%d %lf %s\n", s.n, s.d, s.name);//  打印printf("%s\n", arr);return 0;
}
输出:
100 3.140000 zhangsan
由此可见 sprintf 的作用是:
把格式化的数据转换成对应的字符串

如何从arr里解析出格式化的结构体放进tmp:

#include <stdio.h>struct S
{int n;double d;char name[10];
};int main()
{char arr[100] = { 0 };struct S s = { 100, 3.14, "zhangsan" };struct S tmp = { 0 };// 把一个格式化的数据转换成字符串sprintf(arr, "%d %lf %s\n", s.n, s.d, s.name);// 以字符串形式打印printf("%s\n", arr); // 100 3.140000 zhangsan// 从arr中的字符串中提取一个格式化的数据sscanf(arr, "%d %lf %s", &(tmp.n), &(tmp.d), tmp.name);// 按照格式化的形式打印的printf("%d %lf %s\n", tmp.n, tmp.d, tmp.name); // 100 3.140000 zhangsanreturn 0;
}
由此可见 sscanf 的作用是:
从字符串中读取一个格式化的数据(把一个字符串转换成一个格式化的数据)


优化通讯录程序

文件的版本:

【Contact】结构体+动态内存管理+文件存储实现简易通讯录代码



五、文件的随机读写

1、fseek

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

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

#include <stdio.h>int main()
{FILE* pf = fopen("data.txt", "r");if (NULL == pf){perror("fopen");return -1;}// 读文件 随机读写// 1、读a//int ch = fgetc(pf);//printf("%c\n", ch); // a// 2、如果第一次就要读取'c'fseek(pf, 2, SEEK_SET); // 从起始位置偏移2指向cint ch = fgetc(pf);printf("%c\n", ch); // c// 3、读'b'// 读完c 指向d 要读取b需要从当前位置开始偏移-2fseek(pf, -2, SEEK_CUR);ch = fgetc(pf);printf("%c\n", ch); // bfclose(pf);pf = NULL;return 0;
}



2、ftell

long int ftell ( FILE * stream );

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

计算文件指针相较于起始位置的偏移量:

#include <stdio.h>int main()
{FILE* pf = fopen("data.txt", "r");if (NULL == pf){perror("fopen");return -1;}// 读取'c'fseek(pf, 2, SEEK_SET);int ch = fgetc(pf);printf("%c\n", ch);// 读'b'fseek(pf, -2, SEEK_CUR);ch = fgetc(pf);printf("%c\n", ch);// 计算偏移量// 读取b后指向c 偏移量较起始位置为2int ret = ftell(pf);printf("%d\n", ret); // 2fclose(pf);pf = NULL;return 0;
}


3、rewind

void rewind ( FILE * stream );

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

#include <stdio.h>int main()
{FILE* pf = fopen("data.txt", "r");if (NULL == pf){perror("fopen");return -1;}// 读取'c'fseek(pf, 2, SEEK_SET);int ch = fgetc(pf);printf("%c\n", ch);// 读'b'fseek(pf, -2, SEEK_CUR);ch = fgetc(pf);printf("%c\n", ch);// 计算偏移量int ret = ftell(pf);printf("%d\n", ret); // 2// 让指针回到起始位置// 再次从起始位置打印 还是arewind(pf);ch = fgetc(pf);printf("%c\n", ch); // afclose(pf);pf = NULL;return 0;
}


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

十进制10000的二进制存储:
ASCII形式 / 二进制形式
5字节 4字节

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



七、文件结束判定

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

字符输入函数fgetc返回int,遇到错误或文件结束返回EOF
如果用fgetc读取文件,可以判断fgetc的返回值是否是EOF,来判定文件是否读取结束
文本行输入函数fgets返回起始地址,遇到错误或文件结束返回NULL

#include <stdio.h>int main()
{FILE* pf = fopen("data.txt", "r");if (pf == NULL){perror("fopen");return -1;}int ch = 0;while ((ch = fgetc(pf)) != EOF){printf("%c ", ch);}fclose(pf);pf = NULL;return 0;
}

feof

feof不是用来判断文件是否读取结束的

文本文件的例子:

#include <stdio.h>
#include <stdlib.h>int main(void)
{int c; // 注意:int,非char,要求处理EOFFILE* fp = fopen("test.txt", "r");if (!fp) {perror("File opening failed");return EXIT_FAILURE;}//fgetc 当读取失败的时候或者遇到文件结束的时候,都会返回EOFwhile ((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);fp = NULL;
}

二进制文件的例子:

#include <stdio.h>enum { SIZE = 5 };int main(void)
{double a[SIZE] = { 1.0,2.0,3.0,4.0,5.0 };double b = 0.0;size_t ret_code = 0;FILE* fp = fopen("test.bin", "wb"); // 必须用二进制模式fwrite(a, sizeof(*a), SIZE, fp); // 写 double 的数组fclose(fp);fp = fopen("test.bin", "rb");// 读 double 的数组while ((ret_code = fread(&b, sizeof(double), 1, fp)) >= 1){printf("%lf\n", b);}if (feof(fp))printf("Error reading test.bin: unexpected end of file\n");else if (ferror(fp)) {perror("Error reading test.bin");}fclose(fp);fp = NULL;
}

总结:
feof是当文件读取结束的时候,判断是读取失败结束,还是遇到文件尾结束
ferror 用途:文件读取结束了,判断是不是遇到错误后读取结束



八、文件缓冲区


测试代码:

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

结论:
因为有缓冲区的存在,C语言在操作文件时,需要做刷新缓冲区或者在文件操作结束时关闭文件(fclose关闭文件的时候 也会刷新缓冲区),否则可能导致读写文件问题

文件操作(文件指针+顺序/随机读写)相关推荐

  1. AIR文件操作(三):使用FileStream对象读写文件

    快速上手例: 例1.读xml var testXML:XML; var file:File = File.documentsDirectory.resolvePath("Mousebomb/ ...

  2. java流与文件——操作文件

    [0]README 0.1) 本文描述转自 core java volume 2, 旨在理解 java流与文件--操作文件 的相关知识: 0.2) for source code, please vi ...

  3. Linux——权限|shell运行原理——外壳程序|Linux权限的概念|对人操作|角色和文件操作|文件类型访问权限|修改权限ugo+-|8进制|修改权限|更改文件的拥有

    目录 shell运行原理--外壳程序 Linux权限的概念 对人操作 角色和文件操作 文件类型

  4. C语言基础14——文件操作。文本文件或二进制文件读写。通讯录的改造。文件缓冲区讲解

    目录 为什么使用文件? 什么是文件? 文件的打开和关闭 文件指针 文件的打开和关闭 文件的打开方式 流 重定义文件 文件流 文件的顺序读写 以字符形式读写文本文件 fputc()函数 fgetc()函 ...

  5. Python基础day07 作业解析【文件操作(文件读写、文件夹操作)】

    视频.源码.课件.软件.笔记:超全面Python基础入门教程[十天课程]博客笔记汇总表[黑马程序员] Python基础day07[文件读写.文件夹操作.面向对象(类.对象)] 目录 加强训练 题目1 ...

  6. VC 文件操作(文件查找,打开/保存,读/写,复制/删除/重命名)

    右击项目->属性->字符集:使用多字节字符集. 这样可以使用char到CString的转化. char sRead[20] = ""; CString strtest ...

  7. python文件读取与输出_python基本文件操作(文件输入和输出)

    文件输入输出中常用的文件对象方法: open: 返回一个新的文件对象,调用该对象的上的方法可对文件进行任何操作 readline: 读取一行数据包括结尾的换行符在内 write: 将数据写入文件中 c ...

  8. 【Delphi入门】文件系统(文件分类 文件文本变量 文件操作 文件流操作)

    文件分类 文本文件(TextFile) & 二进制文件(Flie) 二进制形式存放数据占有存储空间较少,但不直观:文本文件与之相反 文件是由相同类型的数据元素组成的序列.在DELPHI中对文件 ...

  9. Linux学习笔记6 文件操作——文件描述符

    基于文件描述符的文件操作 进程一启动,内核就打开了三个描述符,0(标准输入 STDIN),1(标准输出STDOUT), 2(标准错误输出STDERR).Linux用整形数做文件操作,因此称为文件描述符 ...

最新文章

  1. 7-19 支票面额 (C语言)
  2. plsql 参数中in out in的区别讲解
  3. 如何在PySide中使用qrc资源文件
  4. github网址无法访问怎么办?
  5. 我化身保姆为你提供 html 教学服务(6)
  6. 在VMware开启此虚拟机时出现内部错误
  7. 剑指Offer - 面试题66. 构建乘积数组(正反遍历)
  8. C++ 堆区和栈区的区别
  9. acm国际大学上计算机竞赛,ACM国际大学生程序设计竞赛
  10. Vista忘记密码如何登录?
  11. 库依赖关系和开源供应链带来的噩梦
  12. ./configure --prefix --with解释
  13. C语言常量定义#define和const区别解析
  14. 局域网IP扫描工具-OpUtils
  15. 清华大学模拟电子技术视频教程
  16. 10个资源满满的网站,偷偷收藏起来吧!
  17. visual studio 2015无法打开包括文件
  18. 网龙百万3D角色编辑系统介绍
  19. 从大数据的角度看 房价一定会下跌
  20. 重装系统(超详细教程)----大白菜教程

热门文章

  1. mysql动态加载数据库数据库_Mysql动态更新数据库脚本的示例讲解
  2. java合并两个数组_「JAVA」两个数组的交集—力扣每日一题(一)
  3. java 动态树_使用dtree构建动态树型菜单
  4. zabbix 安装(yum)
  5. 硅谷VC想对CIO说这些
  6. 第11章 使用Vsftpd服务传输文件
  7. HDU2111 Saving HDU 【贪心】
  8. 弱鸡儿长乐爆零旅Day1
  9. Linux 文件或文件夹重命名命令mv
  10. hdu3359 Kind of a Blur