第十三章 文件操作

  • 文本文件:将数值型数据的每一位数字作为一个字符以其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. Centos7下常见目录

    /etc/fstab

  2. [LC] 169. Majority Element

    Given an array of size n, find the majority element. The majority element is the element that appear ...

  3. JavaScript设计模式一:工厂模式和构造器模式

    转自:http://segmentfault.com/a/1190000002525792 什么是模式 前阵子准备期末考试,挺累也挺忙的,实在闲不得空来更新文章,今天和大家说说javascript中的 ...

  4. SQL提高性能

    1.对外键建立索引,大数据量时性能提高明显(建索引可以直接[Merge Join],否则还须在查询时生成HASH表作[Hash Join]) 2.尽量少使用inner join,使用left join ...

  5. telnet不是内部或外部命令的问题解决

    在windows DOS 命令窗口中输入telnet命令,出现如下提示信息:     可能是没有安装telnet客户端的原因,又得开始捣鼓了  www.2cto.com     依次点击"开 ...

  6. 三步教你实现MyEclipse的debug远程调试

    MyEclipse远程调试程序是个神奇的东西,有时一个项目本地运行没问题可放到服务器上,同样的条件就是结果不一样:有时服务器上工程出点问题需要远程调测.于是就灰常想看一下程序在远程运行时候的状态,希望 ...

  7. CF-1111C-Creative Snap

    前两天过年,所以两天前的比赛题目现在才来回顾. 这题是一个最平常的递归,加一个剪枝.题目说如果一段距离没有复仇者看守,消耗的能量为A,A一定是正整数.由此可知对于没有复仇者看守的段,不拆一定比拆成两半 ...

  8. Linux(CentOS_7.6)安装Nginx

    1.安装依赖 12 yum -y install gcc zlib zlib-devel pcre-devel openssl openssl-devel 2.下载Nginx并解压 1234567 c ...

  9. jquery.Table实现的翻页功能比较完整漂亮,本想扩展个模版DIV

    jquery.dataTable实现的翻页功能比较完整漂亮,本想提取其的翻页部分,再结合模版DIV,bootstrop实现聊天记息的展示. jquery.Table 与table结合的较紧,不能在很下 ...

  10. mysql-5.7.14-winx64解压版配置

    1.下载最新的MySQL文件并且解压 我的位置是 F:\mysql-5.7.14-winx64 2.F:\mysql-5.7.14-winx64\bin; 添加到环境变量-系统变量-PATH下 3.复 ...