第十三章 文件操作

  • 文本文件:将数值型数据的每一位数字作为一个字符以其ASCII码的形式存储(每一位数字都单独占用一个字节的存储空间)
  • 二进制文件:数据值是以二进制形式存储的

文本文件可以方便地被其他程序读取,且其输出与字符一一对应,便于对字符进行逐个处理和输出,但一般占用的存储空间较大,且需花费ASCII码和字符间的转换时间

  • 字节流:C语言把数据看成是由字节构成的序列
  • 流式文件:输入/输出的数据仅受程序的控制而不受物理符号的控制

缓冲型和非缓冲型文件系统

fopen:

FILE *fopen(const char *filename, const chat *mode);
r 只读
w 只写(覆盖)
a 只写(添加)
+ 读写
b 二进制

fclose:

在文件使用结束后必须关闭文件

int fclose(FILE *fp);

关闭成功,返回0值,否则返回一个非0值

读写文件中的字符:

int fgetc(FILE *fp);

从fp所指的文件中读取一个字符,并将位置指针指向下一个字符,读取成功,返回该字符,读到文件末尾,返回EOF = -1

int fputc(int c, FILE *fp);

将字符c写到文件指针fp所指的文件中,写入错误,返回EOF,否则返回字符c

//L13-1

#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *fp;
char ch;
if ((fp = fopen("C:\\Users\\lenovo\\Desktop\\demo.txt","w")) == NULL) /* 判断文件是否成功打开 */
{
printf("Failure to open demo.txt!\n");
exit(0);
}
ch = getchar();
while (ch != '\n') /* 若键入回车换行符则结束键盘输入和文件写入 */
{
fputc(ch, fp);
ch = getchar();
}
fclose(fp); /* 关闭由函数fopen()打开的文件demo.txt */
return 0;
}

//L13-2

#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *fp;
char ch;
int i;
if ((fp = fopen("C:\\Users\\lenovo\\Desktop\\demo.bin","wb")) == NULL) /* 以二进制写方式打开文件 */
{
printf("Failure to open demo.bin!\n");
exit(0);
}
for (i=0; i<128; i++)
{
fputc(i, fp); /* 将ASCII码值在0-127之间的所有字符写入文件 */
}
fclose(fp);
if ((fp = fopen("C:\\Users\\lenovo\\Desktop\\demo.bin","rb")) == NULL) /* 以二进制读方式打开文件 */
{
printf("Failure to open demo.bin!\n");
exit(0);
}
while ((ch = fgetc(fp)) != EOF) /* 从文件中读取字符直到文件末尾 */
{
putchar(ch); /* 在显示器上显示从文件读出的所有字符 */
}
fclose(fp);
return 0;
}
//运行结果

 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~

//L13-3

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main()
{
FILE *fp;
char ch;
int i;
if ((fp = fopen("demo.bin","wb")) == NULL) /* 以二进制写方式打开文件 */
{
printf("Failure to open demo.bin!\n");
exit(0);
}
for (i=0; i<128; i++)
{
fputc(i, fp); /* 将字符的ASCII码值写入文件 */
}
fclose(fp);
if ((fp = fopen("demo.bin","rb")) == NULL) /* 以二进制读方式打开文件 */
{
printf("Failure to open demo.bin!\n");
exit(0);
}
while ((ch = fgetc(fp)) != EOF) /* 从文件中读取字符直到文件末尾 */
{
if (isprint(ch)) /* 判断是否是可打印字符 */
{
printf("%c\t", ch); /* 若是可打印字符,则显示该字符 */
}
else
{
printf("%d\t", ch); /*若非可打印字符,则显示该字符的ASCII码值*/
}
}
fclose(fp);
return 0;
}
//运行结果
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
30 31 ! " # $ % & ' ( ) * + ,
- . / 0 1 2 3 4 5 6 7 8 9 : ;
< = > ? @ A B C D E F G H I J
K L M N O P Q R S T U V W X Y
Z [ \ ] ^ _ ` a b c d e f g h
i j k l m n o p q r s t u v w
x y z { | } ~ 127

feof()用于检查是否到达文件末尾,当文件位置指针指向文件结束符时,返回非0值,否则返回0值

ferror()用于检查是否出现文件错误,如果出现错误返回非0值,否则返回0值

fgets()读写文件中的字符串

char *fgets(char *s, int n, FILE *fp)

函数从fp所指的文件中读取字符串并在字符串末尾添加'\0',然后存入s,最多读取n-1个字符

当读到回车换行符、到达文件尾或读满n-1个字符时,函数返回该字符串的首地址,即指针s的值,读取失败则返回空指针

//L13-4

#include <stdio.h>
#include <stdlib.h>
#define N 80
int main()
{
FILE *fp;
char str[N];
if ((fp = fopen("C:\\Users\\lenovo\\Desktop\\demo.txt","a")) == NULL) /* 以添加方式打开文本文件 */
{
printf("Failure to open demo.txt!\n");
exit(0);
}
gets(str); /* 从键盘读入一个字符串 */
fputs(str, fp); /* 将字符串str写入fp所指的文件 */
fclose(fp);
if ((fp = fopen("C:\\Users\\lenovo\\Desktop\\demo.txt","r")) == NULL) /* 以读方式打开文本文件 */
{
printf("Failure to open demo.txt!\n");
exit(0);
}
fgets(str, N, fp); /* 从fp所指的文件中读出字符串,最多读N-1个字符 */
puts(str); /* 将字符串送到屏幕显示 */
fclose(fp);
return 0;
}
//运行结果
I am happy.
I am a student.I am happy.

与gets()不同的是,fgets()从指定的流读字符串,读到换行符时将换行符也作为字符串的一部分读到字符串中来

同理,与puts()不同的是,fputs()不会在写入文件的字符串末尾加上换行符

按格式读写文件:

int fscanf(FILE *fp, const char *format, ...);
int fprint(FILE *fp, const char *format, ...);

//L13-5

#include  <stdio.h>
#include <stdlib.h>
#define N 30
typedef struct date
{
int year;
int month;
int day;
}DATE;
typedef struct student
{
long studentID; /* 学号 */
char studentName[10]; /* 姓名 */
char studentSex; /* 性别 */
DATE birthday; /* 出生日期 */
int score[4]; /* 4门课程的成绩 */
float aver; /* 平均分 */
}STUDENT;
void InputScore(STUDENT stu[], int n, int m);
void AverScore(STUDENT stu[], int n, int m);
void WritetoFile(STUDENT stu[], int n, int m);
int main()
{
STUDENT stu[N];
int n;
printf("How many student?");
scanf("%d", &n);
InputScore(stu, n, 4);
AverScore(stu, n, 4);
WritetoFile(stu, n, 4);
return 0;
}
/*从键盘输入n个学生的学号、姓名、性别、出生日期以及m门课程的成绩到结构体数组stu中*/
void InputScore(STUDENT stu[], int n, int m)
{
int i, j;
for (i=0; i<n; i++)
{
printf("Input record %d:\n", i+1);
scanf("%ld", &stu[i].studentID);
scanf("%s", stu[i].studentName);
scanf(" %c", &stu[i].studentSex); /* %c前有一个空格 */
scanf("%d", &stu[i].birthday.year);
scanf("%d", &stu[i].birthday.month);
scanf("%d", &stu[i].birthday.day);
for (j=0; j<m; j++)
{
scanf("%d", &stu[i].score[j]);
}
}
}
/* 计算n个学生的m门课程的平均分,存入数组aver中 */
void AverScore(STUDENT stu[], int n, int m)
{
int i, j, sum;
for (i=0; i<n; i++)
{
sum = 0;
for (j=0; j<m; j++)
{
sum = sum + stu[i].score[j];
}
stu[i].aver = (float)sum/m;
}
}
/* 输出n个学生的学号、姓名、性别、出生日期以及m门课程的成绩到文件score.txt中 */
void WritetoFile(STUDENT stu[], int n, int m)
{
FILE *fp;
int i, j;
if ((fp = fopen("C:\\Users\\lenovo\\Desktop\\score.txt","w")) == NULL) /* 以写方式打开文本文件 */
{
printf("Failure to open score.txt!\n");
exit(0);
}
fprintf(fp, "%d\t%d\n", n, m); /*将学生人数和课程门数写入文件*/
for (i=0; i<n; i++)
{
fprintf(fp, "%10ld%8s%3c%6d/%02d/%02d", stu[i].studentID,
stu[i].studentName,
stu[i].studentSex,
stu[i].birthday.year,
stu[i].birthday.month,
stu[i].birthday.day);
for (j=0; j<m; j++)
{
fprintf(fp, "%4d", stu[i].score[j]);
}
fprintf(fp, "%6.1f\n", stu[i].aver);
}
fclose(fp);
}

//L13-6

#include  <stdio.h>
#include <stdlib.h>
#define N 30
typedef struct date
{
int year;
int month;
int day;
}DATE;
typedef struct student
{
long studentID; /* 学号 */
char studentName[10]; /* 姓名 */
char studentSex; /* 性别 */
DATE birthday; /* 出生日期 */
int score[4]; /* 4门课程的成绩 */
float aver; /* 平均分 */
}STUDENT;
void ReadfromFile(STUDENT stu[], int *n, int *m);
void PrintScore(STUDENT stu[], int n, int m);
int main()
{
STUDENT stu[N];
int n, m = 4;
ReadfromFile(stu, &n, &m);
PrintScore(stu, n, m);
return 0;
}
/*从文件中读取学生的学号、姓名、性别、出生日期及成绩到结构体数组stu中*/
void ReadfromFile(STUDENT stu[], int *n, int *m)
{
FILE *fp;
int i, j;
if ((fp = fopen("score.txt","r")) == NULL) /* 以读方式打开文本文件 */
{
printf("Failure to open score.txt!\n");
exit(0);
}
fscanf(fp, "%d\t%d", n, m); /* 从文件中读出学生人数和课程门数 */
for (i=0; i<*n; i++) /*学生人数保存在n指向的存储单元*/
{
fscanf(fp, "%10ld", &stu[i].studentID);
fscanf(fp, "%8s", stu[i].studentName);
fscanf(fp, " %c", &stu[i].studentSex); /* %c前有一个空格 */
fscanf(fp, "%6d/%2d/%2d", &stu[i].birthday.year,
&stu[i].birthday.month,
&stu[i].birthday.day);
for (j=0; j<*m; j++) /*课程门数保存在m指向的存储单元*/
{
fscanf(fp, "%4d", &stu[i].score[j]);
}
fscanf(fp, "%f", &stu[i].aver); /* 不能使用%6.1f格式 */
}
fclose(fp); }
/* 输出n个学生的学号、姓名、性别、出生日期、m门课程的成绩及平均分到屏幕上 */
void PrintScore(STUDENT stu[], int n, int m)
{
int i, j;
for (i=0; i<n; i++)
{
printf("%10ld%8s%3c%6d/%02d/%02d",
stu[i].studentID, stu[i].studentName, stu[i].studentSex,
stu[i].birthday.year, stu[i].birthday.month, stu[i].birthday.day);
for (j=0; j<m; j++)
{
printf("%4d", stu[i].score[j]);
}
printf("%6.1f\n", stu[i].aver);
}
}

按数据块读写文件:

unsigned int fread(void *buffer, unsigned int size, unsigned int conut, FILE *fp);

从fp所指的文件中读取数据块并存储到buffer指向的内存中

buffer是待读入数据的起始地址,size是每个数据块的大小,count是允许读取的数据块

函数返回的是实际读到的数据块个数

unsigned int fwrite(const void *buffer, unsigned int size, unsigned int conut, FILE *fp);

//L13-7

#include  <stdio.h>
#include <stdlib.h>
#define N 30
typedef struct date
{
int year;
int month;
int day;
}DATE;
typedef struct student
{
long studentID; /* 学号 */
char studentName[10]; /* 姓名 */
char studentSex; /* 性别 */
DATE birthday; /* 出生日期 */
int score[4]; /* 4门课程的成绩 */
float aver; /* 4门课程的 平均分 */
}STUDENT;
void InputScore(STUDENT stu[], int n, int m);
void AverScore(STUDENT stu[], int n, int m);
void WritetoFile(STUDENT stu[], int n);
int ReadfromFile(STUDENT stu[]);
void PrintScore(STUDENT stu[], int n, int m);
int main()
{
STUDENT stu[N];
int n, m = 4;
printf("How many student?");
scanf("%d", &n);
InputScore(stu, n, m);
AverScore(stu, n, m);
WritetoFile(stu, n);
n = ReadfromFile(stu);
PrintScore(stu, n, m);
return 0;
}
/*从键盘输入n个学生的学号、姓名、性别、出生日期以及m门课程的成绩到结构体数组stu中*/
void InputScore(STUDENT stu[], int n, int m)
{
int i, j;
for (i=0; i<n; i++)
{
printf("Input record %d:\n", i+1);
scanf("%ld", &stu[i].studentID);
scanf("%s", stu[i].studentName);
scanf(" %c", &stu[i].studentSex); /* %c前有一个空格 */
scanf("%d", &stu[i].birthday.year);
scanf("%d", &stu[i].birthday.month);
scanf("%d", &stu[i].birthday.day);
for (j=0; j<m; j++)
{
scanf("%d", &stu[i].score[j]);
}
}
}
/* 计算n个学生的m门课程的平均分,存入数组aver中 */
void AverScore(STUDENT stu[], int n, int m)
{
int i, j, sum[N];
for (i=0; i<n; i++)
{
sum[i] = 0;
for (j=0; j<m; j++)
{
sum[i] = sum[i] + stu[i].score[j];
}
stu[i].aver = (float)sum[i]/m;
}
}
/* 输出n个学生的学号、姓名、性别、出生日期以及m门课程的成绩到文件student.txt中 */
void WritetoFile(STUDENT stu[], int n)
{
FILE *fp;
if ((fp = fopen("student.txt","w")) == NULL) /* 以写方式打开文本文件 */
{
printf("Failure to open student.txt!\n");
exit(0);
}
fwrite(stu, sizeof(STUDENT), n, fp); /* 按数据块写文件 */
fclose(fp);
}
/*从文件中读取学生的学号、姓名、性别、出生日期及成绩到结构体数组stu中并返回学生数*/
int ReadfromFile(STUDENT stu[])
{
FILE *fp;
int i;
if ((fp = fopen("student.txt","r")) == NULL) /* 以读方式打开文本文件 */
{
printf("Failure to open student.txt!\n");
exit(0);
}
for (i=0; !feof(fp); i++)
{
fread(&stu[i], sizeof(STUDENT), 1, fp); /* 按数据块读文件 */
}
fclose(fp);
printf("Total students is %d.\n", i-1); /* 返回文件中的学生记录数 */
return i-1; /* 返回文件中的学生记录数 */
}
/* 输出n个学生的学号、姓名、性别、出生日期、m门课程的成绩及平均分到屏幕上 */
void PrintScore(STUDENT stu[], int n, int m)
{
int i, j;
for (i=0; i<n; i++)
{
printf("%10ld%8s%3c%6d/%02d/%02d",
stu[i].studentID, stu[i].studentName, stu[i].studentSex,
stu[i].birthday.year, stu[i].birthday.month, stu[i].birthday.day);
for (j=0; j<m; j++)
{
printf("%4d", stu[i].score[j]);
}
printf("%6.1f\n", stu[i].aver);
}
}

文件的随机读写:

不同于顺序读写的是,文件的随机访问允许在文件位置中随机定位,并在文件的任何位置直接读写数据

为了实现文件的定位,在每一个打开的文件中都有一个文件位置指针,也称为文件位置标记,用来指向当前读写文件的位置,它保存了文件中的位置信息

当需要随机读写文件数据时,需要强制移动文件位置指针指向特定的位置

int fseek(FILE *fp, long offset, int fromwhere);

将fp的文件位置指针,从fromwhere开始移动offset个字节,表示下一个要读取的数据的位置

  • fromwhere为SEEK_SET或0,代表文件开始处
  • fromwhere为SEEK_CUR或1,代表文件当前位置
  • fromwhere为SEEK_END或2,代表文件结尾处

void rewind(FILE *fp);

将文件位置指针指向文件首字节,即重置位置指针到文件首部

long ftell(FILE *fp);

用相对于文件起始位置的字节偏移量来表示返回的当前文件位置指针

int fflush(FILE *fp);

无条件地把缓存区中的所有数据写入物理设备

//L13-8

#include  <stdio.h>
#include <stdlib.h>
typedef struct date
{
int year;
int month;
int day;
}DATE;
typedef struct student
{
long studentID; /* 学号 */
char studentName[10]; /* 姓名 */
char studentSex; /* 性别 */
DATE birthday; /* 出生日期 */
int score[4]; /* 4门课程的成绩 */
float aver; /* 平均分 */
}STUDENT;
void SearchinFile(char fileName[], long k);
int main()
{
long k;
printf("Input the searching record number:");
scanf("%ld", &k);
SearchinFile("student.txt", k);
return 0;
}
/* 从文件fileName中查找并显示第k条记录的数据 */
void SearchinFile(char fileName[], long k)
{
FILE *fp;
int j;
STUDENT stu;
if ((fp = fopen(fileName,"r")) == NULL) /* 以读方式打开文本文件 */
{
printf("Failure to open %s!\n", fileName);
exit(0);
}
fseek(fp, (k-1)*sizeof(STUDENT), SEEK_SET);
fread(&stu, sizeof(STUDENT), 1, fp); /* 按数据块读文件 */
printf("%10ld%8s%3c%6d/%02d/%02d",
stu.studentID, stu.studentName, stu.studentSex,
stu.birthday.year, stu.birthday.month, stu.birthday.day);
for (j=0; j<4; j++)
{
printf("%4d", stu.score[j]);
}
printf("%6.1f\n", stu.aver);
fclose(fp);
}

标准输入/输出重定向:

  • 用"<"表示输入重定向
  • 用">"表示输出重定向

C语言程序设计(十三) 文件操作的更多相关文章

  1. C语言样式的文件操作函数

    使用C语言样式的文件操作函数,需要包含stdio.h头文件. 1.打开文件的函数: //oflag的取值为“w”或“r”,分别表示以写或读的方式打开 FILE* fd = fopen(filename ...

  2. Unix/Linux环境C编程入门教程(41) C语言库函数的文件操作详解

     上一篇博客我们讲解了如何使用Linux提供的文件操作函数,本文主要讲解使用C语言提供的文件操作的库函数. 1.函数介绍 fopen(打开文件) 相关函数 open,fclose 表头文件 #in ...

  3. Unix/Linux环境C编程新手教程(41) C语言库函数的文件操作具体解释

     上一篇博客我们解说了怎样使用Linux提供的文件操作函数,本文主要解说使用C语言提供的文件操作的库函数. 1.函数介绍 fopen(打开文件) 相关函数 open,fclose 表头文件 #in ...

  4. 3)Linux程序设计入门--文件操作

    )Linux程序设计入门--文件操作 Linux下文件的操作 前言: 我们在这一节将要讨论linux下文件操作的各个函数. 文件的创建和读写 文件的各个属性 目录文件的操作 管道文件 .文件的创建和读 ...

  5. C语言复习:文件操作

    文件操作专题 C语言文件读写概念 文件分类 按文件的逻辑结构: 记录文件:由具有一定结构的记录组成(定长和不定长) 流式文件:由一个个字符(字节)数据顺序组成 按存储介质: 普通文件:存储介质文件(磁 ...

  6. go语言之行--文件操作、命令行参数、序列化与反序列化详解

    一.简介 文件操作对于我们来说也是非常常用的,在python中使用open函数来对文件进行操作,而在go语言中我们使用os.File对文件进行操作. 二.终端读写 操作终端句柄常量 os.Stdin: ...

  7. C语言基础(20)-文件操作(fopen,getc,fclose)

    一.文件操作 读文件的顺序: 1.先打开文件 2.读写文件 3.关闭文件 1.1 fopen FILE *fopen( const char *path, const char *mode ); 函数 ...

  8. Go语言基础之文件操作

    本文主要介绍了Go语言中文件读写的相关操作. 文件是什么? 计算机中的文件是存储在外部介质(通常是磁盘)上的数据集合,文件分为文本文件和二进制文件. 打开和关闭文件 os.Open()函数能够打开一个 ...

  9. GO学习-(16) Go语言基础之文件操作

    Go语言文件操作 本文主要介绍了Go语言中文件读写的相关操作. 文件是什么? 计算机中的文件是存储在外部介质(通常是磁盘)上的数据集合,文件分为文本文件和二进制文件. 打开和关闭文件 os.Open( ...

  10. C语言中的文件操作

    按照字符的方式读取文件 按照行的方式读取文件 按照数据块的方式读取文件 按照格式化的方式读取文件 文件分类 记录文件:具有一定的结构记录组成,分为定长和不定长两种方式 流式文件:按照一个字符一个字符( ...

随机推荐

  1. 在mysql中生成数据库和数据表

    #创建数据库CREATE DATABASE s4day65 DEFAULT CHARSET utf8; #班级表 CREATE TABLE class (id INT NOT NULL AUTO_IN ...

  2. 12款优秀的 JavaScript 日历和时间选择控件

    这些插件能够帮助  Web 开发人员更快速的实现各种精美的日历和时间选择效果. 1. The Coolest Calendar 界面非常漂亮的一款日期选择插件,有详细的使用文档,最新版本 1.5. 点 ...

  3. 转载-WebSocket协议解析

    现在,很多网站为了实现推送技术,所用的技术都是轮询.轮询是指在特定的时间间隔(如每一秒),由浏览器对服务器发起HTTP请求,然后由服务器返回数据给浏览器.由于HTTP协议是惰性的,只有客户端发起请求, ...

  4. Tomcat源码解析-启动过程分析之主干流程

    Tomcat启动入口就在脚本startup.sh中,具体脚本可以看tomcat的源码,这个启动脚本主要用来判断环境,找到catalina.sh脚本路径,将启动参数传递给catalina.sh执行.ca ...

  5. 使用iframe的好处与坏处详细比拼

    一.使用iframe的坏处 1.搜索引擎的蜘蛛不会识别在iframe中被调用的图片.文本.url等内容的,因为该内容不属于该页面,只是访问的时候被临时的调用,而且在SEO建议中也有提到:"f ...

  6. printf 输出浮点数

    在测试printf函数输出结果时,写了如下代码: /** * printf:格式化输出函数 * printf函数不会按照格式控制而对数据类型进行转换,不管三七二十一, * 抓到二进制数据就按照格式控制 ...

  7. 如何为MyEclipse添加XML文档所使用的DTD

    1.打开MyEclipse,找到菜单栏"Window"---->"Preferences(首选项)": 2.在左侧导航菜单栏找到"MyEclip ...

  8. Mac下如何使用homebrew

    Homebrew简称brew,是Mac OSX上的软件包管理工具,能在Mac中方便的安装软件或者卸载软件. 常用的命令: 搜索软件:brew search 软件名,如brew search wget ...

  9. 模型压缩之Channel Pruning

    论文地址 channel pruning是指给定一个CNN模型,去掉卷积层的某几个输入channel以及相应的卷积核, 并最小化裁剪channel后与原始输出的误差. 可以分两步来解决: channe ...

  10. TableViewComponent v2

    Unity UGUI 自带的 ScrollView 控件不支持复用滚动内容,在数量大的情况下,界面容易卡顿 借鉴其他游戏控件,写了个可复用的滚动组件,扩展.优化了ScrollView TableVie ...