C_13_FILE
FILE
简介:
文件用来存放程序、文档、音频、视频、片等数据的。
文件就是存放在磁盘上的,一些数据的集合。
在windows下可以通过写字板或记事本打开文本文件对文件进行编辑保存。写字板和记事本是微软程序员写的程序,对文件进行打开、显示、读写、关闭。
作为一个程序员,必须掌握编程实现创建、写入、读取文件等操作
对文件的操作是经常要用到的知识,比如:写飞秋软件传送文件等
文本文件与二进制文件
文本文件
基于字符编码,常见编码有 ASCII、UNICODE 等
一般可以使用文本编辑器直接打开
例如:数 5678 的以 ASCII 存储形式为:
ASCII 码:00110101 00110110 00110111 00111000
歌词文件(lrc):文本文件
二进制码文件:
基于值编码,自己根据具体应用,指定某个值是什么意思
把内存中的数据按其在内存中的存储形式原样输出到磁盘上
一般需要自己判断或使用特定软件分析数据格式
例如:数 5678 的存储形式为:
二进制码:00010110 00101110
音频文件(mp3):二进制文件
图片文件(bmp)文件,一个像素点由两个字节来描述*****######&&&&&
*代表红色的值
#代表绿色的值
&代表蓝色的值
二进制文件以位来表示一个意思。
文本文件、二进制文件对比:
译码:
文本文件编码基于字符定长,译码容易些;
二进制文件编码是变长的,译码难一些(不同的二进制文件格式,有不同的译码方式)。
空间利用率:
二进制文件用一个比特来代表一个意思(位操作);
而文本文件任何一个意思至少是一个字符。
二进制文件,空间利用率高。
可读性:
文本文件用通用的记事本工具就几乎可以浏览所有文本文件
二进制文件需要一个具体的文件解码器,比如读 BMP 文件,必须用读图软件
磁盘文件与设备文件
磁盘文件
指一组相关数据的有序集合,通常 存储在外部介质(如磁盘)上,使用时才调入内存.
如,我们在计算机上见到的文本文档,图片,视频,音频,等文件
设备文件
在操作系统中把每一个与主机相连的输入、输出设备看着是一个文件,把他们的输入、输出等同于对磁盘文件的读和写
键盘:标准输入文件,stdin
屏幕:标准输出文件,stdout
其他设备:打印机,触摸屏,摄像头,音响等
在Linux操作系统中,每一个外部设备都在/dev目录下有对应的一个设备文件,我们程序中想要操作设备,就必须对其所对应的文件进行操作
stdin: 标准输入 默认为当前终端(键盘)
我们使用的 scanf、getchar 函数默认从此终端获得数据
stdout:标准输出 默认为当前终端(屏幕)
我们使用的 printf、puts 函数默认输出信息到此终端
stderr:标准错误输出设备文件 默认为当前终端(屏幕)
当我们程序出错使用:perror 函数时信息打印在此终端
标准 io 库函数对磁盘文件的读写特点
文件缓冲区
缓冲区的目的:提高磁盘使用效率。
刷新缓冲区的情况
1, 行刷新
2, 满刷新
3, 强制刷新
4, 关闭刷新
行刷新
缓冲区
触发行刷新
满刷新
强制刷新
关闭刷新
无刷新
:无缓冲区概念 写数据就立马进入文件 读数据立马进入内存
在读写文件的时候通过系统调用io(read write)对文件进行读写数据这个时候是无缓冲的,即写数据会立马进入文件,读数据会立马进入内存
概述: 系统提供的用于描述文件的结构体
typedef struct { short level; //缓冲区“满”或“空”的程度 unsigned flags; //文件状态标志 char fd; //文件描述符 unsigned charhold; //如无缓冲区不读取字符 short bsize; //缓冲区的大小 unsigned char *buffer; //数据缓冲区的位置 unsigned ar*curp; //指针,当前的指向 unsigned istemp; //临时文件,指示器 shorttoken; //用于有效性检查 }FILE; //在缓冲文件系统中,每个被使用的文件都要在内存中开辟一块 //FILE 类型的区域,存放与操作文件相关的信息
注意
> FILE是用来描述文件的结构体 > FILE *就可以指向一个文件 > FILE *被称为文件指针
文件操作函数
1 fopen
作用: 打开文件
语法:
#include <stdio.h>
FILE *fopen(const char *path, const char *mode); // 参数1 文件路径 相对绝对都行 参数2 对文件操作的选择 r w a
参数:
path:打开的文件地址
相对路径
绝对路径
mode:打开的模式:
r:只读
特点:
文件不存在返回NULL,文件存在返回文件指针
w:只写
特点:
文件不存在,创建文件.文件存在清空文件原内容,在打开,文件打不开(如:只读文件),返回NULL
a:追加
特点:
文件不存在,创建文件.文件存在原文件末尾操作
+: 同时以读写打开指定文件
分类:
r+: 以可读、可写的方式打开文件(不创建新文件)
w+: 以可读、可写的方式打开文件(文件不存在,创建文件,文件存在清空原内容,打开)
a+:以添加方式打开文件,打开文件并在末尾更改文件(如果文件不存在,则创建文件)
b:二进制文件
t:文本文件
rb:二进制文件只读
wb:二进制文件只写
ab:二进制文件追加
返回值: 打开的文件的文件指针
示例:
FILE *file = fopen("./test.txt", "r");
if (file == NULL) {
printf("无法打开文件\n");
return 1;
}
2 fclose
作用: 关闭文件
语法:
#include <stdio.h> int fclose(FILE *stream); 参数: fp:要关闭的文件指针 返回值: 0:关闭成功 非0:关闭失败
3 fgetc
作用
一次读取一个字符
语法:
所属头:
stdio.h
函数:
int fgetc(FILE *stream);
参数:
读取的文件指针
返回值:
读取到的字符
注意:
以t的方式:读到文件结尾返回EOF,EOF是在stdio.h文件中定义的符号常量,值为-1
以b的方式:读到文件结尾,使用 feof(后面会讲)判断结尾
4 fputc
作用:写入一个字符
语法
函数头:
stdio.h
函数:
int fputc(int c, FILE *stream)
参数:
c:写入的数据
stream:写入的文件指针
返回值:
如果输出成功,则返回输出的字节值;
如果输出失败,则返回一个EOF。
5 fgets
作用
# 一次读取一个字符串 只要不出现 \n 就是一个字符串 因为在一行
语法
函数头: stdio.h
函数: char *fgets(char *s,int size,FILE *stream);
示例:
参数:
s:存储读取到的字符串的变量
size:这是要读取的最大字符数(包括最后的空字符)。通常是使用以str传递的数组长度
stream:读取的文件指针
返回值:
成功返回 读取的字符
失败返回 NULL
注意:
读取到换行或文件结束
#include <stdio.h>
int main(int argc, char const *argv[])
{
char arr[40];
fgets(arr,40,stdin); // 从标准输入读取字符串到 arr 中
for (int i = 0; i < 40; i++)
{
printf("%c",arr[i]);
}
return 0;
}
6 fputs
作用 一次写入一个字符串
语法
函数头:
stdio.h
函数:
int fputs(const char *s, FILE *stream);
参数:
s:写入的字符串
stream:写入的文件指针
返回值:
成功返回写入的字节数
失败返回-1
7 fread 【**】
作用:一次读取n块
语法:
函数头
stdio.h
函数
size_t fwrite(viod *ptr,size_t size,size_t nmemb,FILE *stream)
参数:
ptr:指向带有最小尺寸的size*nmemb字节的内存块的指针
size:读取的每个元素的大小,单位字节
nmemb:读取的元素个数
stream:读取的文件指针
返回值:
实际读到的块数
示例:
char *info = (char *)calloc(1, len); //动态开辟内存 分配的内存大小为 len 个字节
fread(info, len, n, file);
参数1 表示动态开辟用来存储读取数据的内存
参数2 表示每个数据块的大小(以字节为单位)
参数3 n 表示要读取的数据块数量。
参数4 表示从那个文件中读
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{
FILE *file = fopen("./test.txt", "r");
if (file == NULL) {
printf("无法打开文件\n");
return 1;
}
fseek(file, 0, 2); //参数1是文件指针,参数2 0 表示偏移量为 0,参数3 2 表示从文件末尾开始偏移。
int len = ftell(file);
rewind(file); // 文件指针重置到文件的开头。
char *info = (char *)calloc(1, len); //动态开辟内存 分配的内存大小为 len 个字节
//从文件file 中读取数据到 info 所指向的内存中 len 表示每个数据块的大小(以字节为单位),1 表示要读取的数据块数量。
if (fread(info, len, 1, file)!= 1) {
printf("读取文件失败\n");
free(info);
fclose(file);
return 1;
}
fclose(file); //关闭文件。
printf("%s\n",info); //确保正确的字符串 以\0 结尾
free(info);
return 0;
}
8 fwrite 【**】
一次写n块
语法:
函数头
stdio.h
函数
size_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);
参数:
ptr:这是指向要被写入的元素数组的指针。
size:这是要被写入的每个元素的大小,以字节为单位。
nmemb: 这是元素的个数,每个元素的大小为 size 字节。
stream:这是指向 FILE 对象的指针,该 FILE 对象指定了一个输出流。
返回值:
实际写入的块数
9 fprintf
作用 给文件中格式化输入内容
语法:
函数头:
stdio.h
函数
int fprintf(FILE *stream, const char *format, ...)
参数:
stream:文件指针
format:格式化字符串
...:输出数据列表
返回值:
成功:则返回写入的字符总数,
失败:返回一个负数
10 fscanf
作用:
格式化读取
语法:
函数头:
stdio.h
函数:
int fscanf(FILE *stream, const char *format, ...)
参数:
stream:文件指针
format:格式化字符串
...:输入数据列表
返回值:
成功:该函数返回成功匹配和赋值的个数。如果到达文件末尾或发生读错误,则返回EOF
11 rewind 【**】
作用:
将游标移动到文件开始
函数头
stdio.h
函数
void rewind(FILE *stream)
参数
指针文件
12 ftell 【**】
作用: 测试游标到文件开始位置的字节数
语法:
函数头:
stdio.h
函数:
long int ftell(FILE *stream)
参数:
文件指针
返回值:
文件读写位置距文件开始的字节数
#include <stdio.h>
int main(int argc, char const *argv[])
{
FILE *file = fopen("./小说.txt","w+"); //以可读可写的方式打开
fputs("张十一",file); // 写入一个字符串
fseek(file,0,2); // 将游标移动到尾部 参数1 文件 参数2 偏移量 参数3 0 开始 1当前位置 2 尾部
int len = ftell(file); // 要 测量的文件指针
printf("字节数 = %d\n",len);
fclose(file); //关闭文件
return 0;
}
13 fseek 【**】
作用:
移动游标位置
语法:
函数头:
stdio.h
函数:
int fseek(FILE *stream, long int offset, int whence)
参数:
stream:文件指针
offset:相对于whence的偏移量
whence:位置,0,开始,1,当前位置,2,结尾
一次性读取文件中的所有内容
FILE *file = fopen("./test.txt", "r");
if (file == NULL) {
printf("无法打开文件\n");
return 1;
}
fseek(file, 0, 2); //参数1是文件指针,参数2 0 表示偏移量为 0,参数3 2 表示从文件末尾开始偏移。
int len = ftell(file);
rewind(file); // 文件指针重置到文件的开头。
char *info = (char *)calloc(1, len+1); //动态开辟内存 分配的内存大小为 len 个字节
//从文件file 中读取数据到 info 所指向的内存中 len 表示每个数据块的大小(以字节为单位),1 表示要读取的数据块数量。
if (fread(info, len, 1, file)!= 1) {
printf("读取文件失败\n");
free(info);
fclose(file);
return 1;
}
fclose(file); //关闭文件。
printf("%s\n",info); //确保正确的字符串 以\0 结尾
free(info);
2 makefile
概述:
编写编译命令的文件
文件编写格式
目标:依赖文件列表
<Tab>命令列表
解释:
1、目标:
通常是要产生的文件名称,目标可以是可执行文件或其它 obj 文件,也可是一个动作的名称
2、依赖文件:
是用来输入从而产生目标的文件
一个目标通常有几个依赖文件(可以没有)
3、命令:
make 执行的动作,一个规则可以含几个命令(可以没有)
有多个命令时,每个命令占一行
如:在makefile文件中编写
main:main.c
gcc main.c -o main
clear:
rm main
其中main就是目标,main.c就是依赖文件,gcc main.c -o main就是命令
注意:
当目标后没有依赖文件,我们将其称为假想目标
变量
分类
系统变量(了解)
由系统提供的变量 make工具会拷贝系统的环境变量并将其设置为 makefile 的变量,在 makefile 中可直接读取或修改拷贝后的变量。 查看系统变量命令 env 修改或添加系统变量 export 变量名=值 注意 export是导入的意思 注意: 只是临时修改,也就是只在当前dos框中生效, 当dos关闭后,将不在存在 如:makefile编写如下 main:main.o myutils.o gcc main.o myutils.o -o main clear: rm main *.o myprint: echo ${PWD}
自定义变量
程序员在编写makefile文件中自定义的变量
预定义变量
make命令提供的变量
自定义变量
语法
定义 变量名=变量值 使用 取值:$(变量名)或${变量名} 拼接:变量名+=值
注意:
> 1、makefile 变量名可以以数字开头 > 2、变量是大小写敏感的 > 3、变量一般都在 makefile 的头部定义 > 4、变量几乎可在 makefile 的任何地方使用
预定义变量
makefile 中有许多预定义变量,这些变量具有特殊的含义,可在 makefile 中直接使 用。 $@ 目标名 $< 依赖文件列表中的第一个文件 $^ 依赖文件列表中除去重复文件的部分 以下为了解 AR 归档维护程序的程序名,默认值为 ar ARFLAGS 归档维护程序的选项 AS 汇编程序的名称,默认值为 as ASFLAGS 汇编程序的选项 CC C 编译器的名称,默认值为 gcc CFLAGS C 编译器的选项 CPP C 预编译器的名称,默认值为$(CC) -E CPPFLAGS C 预编译的选项 CXX C++编译器的名称,默认值为 g++ CXXFLAGS C++编译器的选项
编写模板
EXEC = 可执行程序名
OBJ = 二进制文件名列表
FLAGS = -Wall -g # 忽略一些警告
$(EXEC):$(OBJ)
$(CC) $(OBJ) -o $(EXEC) $(-Wall -g)
二进制文件名1.o:源文件名1.c
$(CC) -c 源文件名.c -o 二进制文件名.o
二进制文件名2.o:源文件名2.c
$(CC) -c 源文件名.c -o 二进制文件名.o
clear:
rm $(EXEC) *.o
注意:
源文件名与二进制文件名相同
示例:
EXEC = main
OBJ = main.o utils.o
FLAGS = -Wall -g
CC = gcc
$(EXEC):$(OBJ)
$(CC) $(OBJ) -o $(EXEC) $(-Wall -g)
main.o:main.c
$(CC) -c main.c -o main.o
utils.o:utils.c
$(CC) -c utils.c -o utils.o
clear:
rm $(EXEC) *.o
3 make命令
概述
解析makefile文件的命令
检查make命令是否存在
- make --version
- which make
GNU Make名词
GNU make 是一种代码维护工具, make 工具会根据 makefile 文件定义的规则和步
骤,完成整个软件项目的代码维护工作
优点:
1、管理我们的源文件
2、会检查每个源文件是否被修改 只会再次只编译修改过的源文件(提高编译效
率)
缺点:
makefile文件:在Window上的集成开发环境下,会自动生成, 在Linux下需要手
动编写。
使用
语法:
make 目标
注意:目标可以没有,默认执行第一个目标
注意:
1、make 默认在工作目录中寻找名为 GNUmakefile、makefile、Makefile 的文件作为 makefile 输入文件
2、-f 可以指定以上名字以外的文件作为 makefile 输入文件
3、若使用 make 命令时没有指定目标,则 make 工具默认会实现 makefile 文件内的第一个目标,然后退出。
如:在控制台输入
1,输入make,默认执行makefile文件中第一个目标中命令
2,输入make 目标,执行makefile文件中指定的目标中的命令
3,当makefile的文件名不是GNUmakefile、makefile、Makefile时,可以输入make -f 文件名,指makefile文件
make命令
概述
解析makefile文件的命令
检查make命令是否存在
- make --version
- which make
GNU Make名词
GNU make 是一种代码维护工具, make 工具会根据 makefile 文件定义的规则和步
骤,完成整个软件项目的代码维护工作
优点:
1、管理我们的源文件
2、会检查每个源文件是否被修改 只会再次只编译修改过的源文件(提高编译效
率)
缺点:
makefile文件:在Window上的集成开发环境下,会自动生成, 在Linux下需要手
动编写。
使用
语法:
make 目标
注意:目标可以没有,默认执行第一个目标
注意:
1、make 默认在工作目录中寻找名为 GNUmakefile、makefile、Makefile 的文件作为 makefile 输入文件
2、-f 可以指定以上名字以外的文件作为 makefile 输入文件
3、若使用 make 命令时没有指定目标,则 make 工具默认会实现 makefile 文件内的第一个目标,然后退出。
如:在控制台输入
1,输入make,默认执行makefile文件中第一个目标中命令
2,输入make 目标,执行makefile文件中指定的目标中的命令
3,当makefile的文件名不是GNUmakefile、makefile、Makefile时,可以输入make -f 文件名,指makefile文件